Blame lib/strtol.c

Packit Service fdd496
/* Convert string representation of a number into an integer value.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1991-1992, 1994-1999, 2003, 2005-2007, 2009-2017 Free Software
Packit Service fdd496
   Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   NOTE: The canonical source of this file is maintained with the GNU C
Packit Service fdd496
   Library.  Bugs can be reported to bug-glibc@gnu.org.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify it
Packit Service fdd496
   under the terms of the GNU General Public License as published by the
Packit Service fdd496
   Free Software Foundation; either version 3 of the License, or any
Packit Service fdd496
   later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
#ifdef _LIBC
Packit Service fdd496
# define USE_NUMBER_GROUPING
Packit Service fdd496
#else
Packit Service fdd496
# include <config.h>
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#include <ctype.h>
Packit Service fdd496
#include <errno.h>
Packit Service fdd496
#ifndef __set_errno
Packit Service fdd496
# define __set_errno(Val) errno = (Val)
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#include <limits.h>
Packit Service fdd496
#include <stddef.h>
Packit Service fdd496
#include <stdlib.h>
Packit Service fdd496
#include <string.h>
Packit Service fdd496
Packit Service fdd496
#ifdef USE_NUMBER_GROUPING
Packit Service fdd496
# include "../locale/localeinfo.h"
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Nonzero if we are defining 'strtoul' or 'strtoull', operating on
Packit Service fdd496
   unsigned integers.  */
Packit Service fdd496
#ifndef UNSIGNED
Packit Service fdd496
# define UNSIGNED 0
Packit Service fdd496
# define INT LONG int
Packit Service fdd496
#else
Packit Service fdd496
# define INT unsigned LONG int
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Determine the name.  */
Packit Service fdd496
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit Service fdd496
# if UNSIGNED
Packit Service fdd496
#  ifdef USE_WIDE_CHAR
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol __wcstoull_l
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol __wcstoul_l
Packit Service fdd496
#   endif
Packit Service fdd496
#  else
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol __strtoull_l
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol __strtoul_l
Packit Service fdd496
#   endif
Packit Service fdd496
#  endif
Packit Service fdd496
# else
Packit Service fdd496
#  ifdef USE_WIDE_CHAR
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol __wcstoll_l
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol __wcstol_l
Packit Service fdd496
#   endif
Packit Service fdd496
#  else
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol __strtoll_l
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol __strtol_l
Packit Service fdd496
#   endif
Packit Service fdd496
#  endif
Packit Service fdd496
# endif
Packit Service fdd496
#else
Packit Service fdd496
# if UNSIGNED
Packit Service fdd496
#  ifdef USE_WIDE_CHAR
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol wcstoull
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol wcstoul
Packit Service fdd496
#   endif
Packit Service fdd496
#  else
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol strtoull
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol strtoul
Packit Service fdd496
#   endif
Packit Service fdd496
#  endif
Packit Service fdd496
# else
Packit Service fdd496
#  ifdef USE_WIDE_CHAR
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol wcstoll
Packit Service fdd496
#   else
Packit Service fdd496
#    define strtol wcstol
Packit Service fdd496
#   endif
Packit Service fdd496
#  else
Packit Service fdd496
#   ifdef QUAD
Packit Service fdd496
#    define strtol strtoll
Packit Service fdd496
#   endif
Packit Service fdd496
#  endif
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* If QUAD is defined, we are defining 'strtoll' or 'strtoull',
Packit Service fdd496
   operating on 'long long int's.  */
Packit Service fdd496
#ifdef QUAD
Packit Service fdd496
# define LONG long long
Packit Service fdd496
# define STRTOL_LONG_MIN LLONG_MIN
Packit Service fdd496
# define STRTOL_LONG_MAX LLONG_MAX
Packit Service fdd496
# define STRTOL_ULONG_MAX ULLONG_MAX
Packit Service fdd496
Packit Service fdd496
/* The extra casts in the following macros work around compiler bugs,
Packit Service fdd496
   e.g., in Cray C 5.0.3.0.  */
Packit Service fdd496
Packit Service fdd496
/* True if the arithmetic type T is signed.  */
Packit Service fdd496
# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
Packit Service fdd496
Packit Service fdd496
/* Minimum and maximum values for integer types.
Packit Service fdd496
   These macros have undefined behavior for signed types that either
Packit Service fdd496
   have padding bits or do not use two's complement.  If this is a
Packit Service fdd496
   problem for you, please let us know how to fix it for your host.  */
Packit Service fdd496
Packit Service fdd496
/* The maximum and minimum values for the integer type T.  */
Packit Service fdd496
# define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
Packit Service fdd496
# define TYPE_MAXIMUM(t)                                                 \
Packit Service fdd496
   ((t) (! TYPE_SIGNED (t)                                               \
Packit Service fdd496
         ? (t) -1                                                        \
Packit Service fdd496
         : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
Packit Service fdd496
Packit Service fdd496
# ifndef ULLONG_MAX
Packit Service fdd496
#  define ULLONG_MAX TYPE_MAXIMUM (unsigned long long)
Packit Service fdd496
# endif
Packit Service fdd496
# ifndef LLONG_MAX
Packit Service fdd496
#  define LLONG_MAX TYPE_MAXIMUM (long long int)
Packit Service fdd496
# endif
Packit Service fdd496
# ifndef LLONG_MIN
Packit Service fdd496
#  define LLONG_MIN TYPE_MINIMUM (long long int)
Packit Service fdd496
# endif
Packit Service fdd496
Packit Service fdd496
# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
Packit Service fdd496
   /* Work around gcc bug with using this constant.  */
Packit Service fdd496
   static const unsigned long long int maxquad = ULLONG_MAX;
Packit Service fdd496
#  undef STRTOL_ULONG_MAX
Packit Service fdd496
#  define STRTOL_ULONG_MAX maxquad
Packit Service fdd496
# endif
Packit Service fdd496
#else
Packit Service fdd496
# define LONG long
Packit Service fdd496
# define STRTOL_LONG_MIN LONG_MIN
Packit Service fdd496
# define STRTOL_LONG_MAX LONG_MAX
Packit Service fdd496
# define STRTOL_ULONG_MAX ULONG_MAX
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* We use this code also for the extended locale handling where the
Packit Service fdd496
   function gets as an additional argument the locale which has to be
Packit Service fdd496
   used.  To access the values we have to redefine the _NL_CURRENT
Packit Service fdd496
   macro.  */
Packit Service fdd496
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit Service fdd496
# undef _NL_CURRENT
Packit Service fdd496
# define _NL_CURRENT(category, item) \
Packit Service fdd496
  (current->values[_NL_ITEM_INDEX (item)].string)
Packit Service fdd496
# define LOCALE_PARAM , loc
Packit Service fdd496
# define LOCALE_PARAM_PROTO , __locale_t loc
Packit Service fdd496
#else
Packit Service fdd496
# define LOCALE_PARAM
Packit Service fdd496
# define LOCALE_PARAM_PROTO
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifdef USE_WIDE_CHAR
Packit Service fdd496
# include <wchar.h>
Packit Service fdd496
# include <wctype.h>
Packit Service fdd496
# define L_(Ch) L##Ch
Packit Service fdd496
# define UCHAR_TYPE wint_t
Packit Service fdd496
# define STRING_TYPE wchar_t
Packit Service fdd496
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit Service fdd496
#  define ISSPACE(Ch) __iswspace_l ((Ch), loc)
Packit Service fdd496
#  define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
Packit Service fdd496
#  define TOUPPER(Ch) __towupper_l ((Ch), loc)
Packit Service fdd496
# else
Packit Service fdd496
#  define ISSPACE(Ch) iswspace (Ch)
Packit Service fdd496
#  define ISALPHA(Ch) iswalpha (Ch)
Packit Service fdd496
#  define TOUPPER(Ch) towupper (Ch)
Packit Service fdd496
# endif
Packit Service fdd496
#else
Packit Service fdd496
# define L_(Ch) Ch
Packit Service fdd496
# define UCHAR_TYPE unsigned char
Packit Service fdd496
# define STRING_TYPE char
Packit Service fdd496
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit Service fdd496
#  define ISSPACE(Ch) __isspace_l ((Ch), loc)
Packit Service fdd496
#  define ISALPHA(Ch) __isalpha_l ((Ch), loc)
Packit Service fdd496
#  define TOUPPER(Ch) __toupper_l ((Ch), loc)
Packit Service fdd496
# else
Packit Service fdd496
#  define ISSPACE(Ch) isspace (Ch)
Packit Service fdd496
#  define ISALPHA(Ch) isalpha (Ch)
Packit Service fdd496
#  define TOUPPER(Ch) toupper (Ch)
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#define INTERNAL(X) INTERNAL1(X)
Packit Service fdd496
#define INTERNAL1(X) __##X##_internal
Packit Service fdd496
#define WEAKNAME(X) WEAKNAME1(X)
Packit Service fdd496
Packit Service fdd496
#ifdef USE_NUMBER_GROUPING
Packit Service fdd496
/* This file defines a function to check for correct grouping.  */
Packit Service fdd496
# include "grouping.h"
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Convert NPTR to an 'unsigned long int' or 'long int' in base BASE.
Packit Service fdd496
   If BASE is 0 the base is determined by the presence of a leading
Packit Service fdd496
   zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
Packit Service fdd496
   If BASE is < 2 or > 36, it is reset to 10.
Packit Service fdd496
   If ENDPTR is not NULL, a pointer to the character after the last
Packit Service fdd496
   one converted is stored in *ENDPTR.  */
Packit Service fdd496
Packit Service fdd496
INT
Packit Service fdd496
INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
Packit Service fdd496
                   int base, int group LOCALE_PARAM_PROTO)
Packit Service fdd496
{
Packit Service fdd496
  int negative;
Packit Service fdd496
  register unsigned LONG int cutoff;
Packit Service fdd496
  register unsigned int cutlim;
Packit Service fdd496
  register unsigned LONG int i;
Packit Service fdd496
  register const STRING_TYPE *s;
Packit Service fdd496
  register UCHAR_TYPE c;
Packit Service fdd496
  const STRING_TYPE *save, *end;
Packit Service fdd496
  int overflow;
Packit Service fdd496
Packit Service fdd496
#ifdef USE_NUMBER_GROUPING
Packit Service fdd496
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit Service fdd496
  struct locale_data *current = loc->__locales[LC_NUMERIC];
Packit Service fdd496
# endif
Packit Service fdd496
  /* The thousands character of the current locale.  */
Packit Service fdd496
  wchar_t thousands = L'\0';
Packit Service fdd496
  /* The numeric grouping specification of the current locale,
Packit Service fdd496
     in the format described in <locale.h>.  */
Packit Service fdd496
  const char *grouping;
Packit Service fdd496
Packit Service fdd496
  if (group)
Packit Service fdd496
    {
Packit Service fdd496
      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
Packit Service fdd496
      if (*grouping <= 0 || *grouping == CHAR_MAX)
Packit Service fdd496
        grouping = NULL;
Packit Service fdd496
      else
Packit Service fdd496
        {
Packit Service fdd496
          /* Figure out the thousands separator character.  */
Packit Service fdd496
# if defined _LIBC || defined _HAVE_BTOWC
Packit Service fdd496
          thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
Packit Service fdd496
          if (thousands == WEOF)
Packit Service fdd496
            thousands = L'\0';
Packit Service fdd496
# endif
Packit Service fdd496
          if (thousands == L'\0')
Packit Service fdd496
            grouping = NULL;
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    grouping = NULL;
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  if (base < 0 || base == 1 || base > 36)
Packit Service fdd496
    {
Packit Service fdd496
      __set_errno (EINVAL);
Packit Service fdd496
      return 0;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  save = s = nptr;
Packit Service fdd496
Packit Service fdd496
  /* Skip white space.  */
Packit Service fdd496
  while (ISSPACE (*s))
Packit Service fdd496
    ++s;
Packit Service fdd496
  if (*s == L_('\0'))
Packit Service fdd496
    goto noconv;
Packit Service fdd496
Packit Service fdd496
  /* Check for a sign.  */
Packit Service fdd496
  if (*s == L_('-'))
Packit Service fdd496
    {
Packit Service fdd496
      negative = 1;
Packit Service fdd496
      ++s;
Packit Service fdd496
    }
Packit Service fdd496
  else if (*s == L_('+'))
Packit Service fdd496
    {
Packit Service fdd496
      negative = 0;
Packit Service fdd496
      ++s;
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    negative = 0;
Packit Service fdd496
Packit Service fdd496
  /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
Packit Service fdd496
  if (*s == L_('0'))
Packit Service fdd496
    {
Packit Service fdd496
      if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
Packit Service fdd496
        {
Packit Service fdd496
          s += 2;
Packit Service fdd496
          base = 16;
Packit Service fdd496
        }
Packit Service fdd496
      else if (base == 0)
Packit Service fdd496
        base = 8;
Packit Service fdd496
    }
Packit Service fdd496
  else if (base == 0)
Packit Service fdd496
    base = 10;
Packit Service fdd496
Packit Service fdd496
  /* Save the pointer so we can check later if anything happened.  */
Packit Service fdd496
  save = s;
Packit Service fdd496
Packit Service fdd496
#ifdef USE_NUMBER_GROUPING
Packit Service fdd496
  if (group)
Packit Service fdd496
    {
Packit Service fdd496
      /* Find the end of the digit string and check its grouping.  */
Packit Service fdd496
      end = s;
Packit Service fdd496
      for (c = *end; c != L_('\0'); c = *++end)
Packit Service fdd496
        if ((wchar_t) c != thousands
Packit Service fdd496
            && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
Packit Service fdd496
            && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
Packit Service fdd496
          break;
Packit Service fdd496
      if (*s == thousands)
Packit Service fdd496
        end = s;
Packit Service fdd496
      else
Packit Service fdd496
        end = correctly_grouped_prefix (s, end, thousands, grouping);
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
#endif
Packit Service fdd496
    end = NULL;
Packit Service fdd496
Packit Service fdd496
  cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
Packit Service fdd496
  cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
Packit Service fdd496
Packit Service fdd496
  overflow = 0;
Packit Service fdd496
  i = 0;
Packit Service fdd496
  for (c = *s; c != L_('\0'); c = *++s)
Packit Service fdd496
    {
Packit Service fdd496
      if (s == end)
Packit Service fdd496
        break;
Packit Service fdd496
      if (c >= L_('0') && c <= L_('9'))
Packit Service fdd496
        c -= L_('0');
Packit Service fdd496
      else if (ISALPHA (c))
Packit Service fdd496
        c = TOUPPER (c) - L_('A') + 10;
Packit Service fdd496
      else
Packit Service fdd496
        break;
Packit Service fdd496
      if ((int) c >= base)
Packit Service fdd496
        break;
Packit Service fdd496
      /* Check for overflow.  */
Packit Service fdd496
      if (i > cutoff || (i == cutoff && c > cutlim))
Packit Service fdd496
        overflow = 1;
Packit Service fdd496
      else
Packit Service fdd496
        {
Packit Service fdd496
          i *= (unsigned LONG int) base;
Packit Service fdd496
          i += c;
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Check if anything actually happened.  */
Packit Service fdd496
  if (s == save)
Packit Service fdd496
    goto noconv;
Packit Service fdd496
Packit Service fdd496
  /* Store in ENDPTR the address of one character
Packit Service fdd496
     past the last character we converted.  */
Packit Service fdd496
  if (endptr != NULL)
Packit Service fdd496
    *endptr = (STRING_TYPE *) s;
Packit Service fdd496
Packit Service fdd496
#if !UNSIGNED
Packit Service fdd496
  /* Check for a value that is within the range of
Packit Service fdd496
     'unsigned LONG int', but outside the range of 'LONG int'.  */
Packit Service fdd496
  if (overflow == 0
Packit Service fdd496
      && i > (negative
Packit Service fdd496
              ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
Packit Service fdd496
              : (unsigned LONG int) STRTOL_LONG_MAX))
Packit Service fdd496
    overflow = 1;
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  if (overflow)
Packit Service fdd496
    {
Packit Service fdd496
      __set_errno (ERANGE);
Packit Service fdd496
#if UNSIGNED
Packit Service fdd496
      return STRTOL_ULONG_MAX;
Packit Service fdd496
#else
Packit Service fdd496
      return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
Packit Service fdd496
#endif
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Return the result of the appropriate sign.  */
Packit Service fdd496
  return negative ? -i : i;
Packit Service fdd496
Packit Service fdd496
noconv:
Packit Service fdd496
  /* We must handle a special case here: the base is 0 or 16 and the
Packit Service fdd496
     first two characters are '0' and 'x', but the rest are no
Packit Service fdd496
     hexadecimal digits.  This is no error case.  We return 0 and
Packit Service fdd496
     ENDPTR points to the 'x'.  */
Packit Service fdd496
  if (endptr != NULL)
Packit Service fdd496
    {
Packit Service fdd496
      if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
Packit Service fdd496
          && save[-2] == L_('0'))
Packit Service fdd496
        *endptr = (STRING_TYPE *) &save[-1];
Packit Service fdd496
      else
Packit Service fdd496
        /*  There was no number to convert.  */
Packit Service fdd496
        *endptr = (STRING_TYPE *) nptr;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return 0L;
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* External user entry point.  */
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
INT
Packit Service fdd496
#ifdef weak_function
Packit Service fdd496
weak_function
Packit Service fdd496
#endif
Packit Service fdd496
strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr,
Packit Service fdd496
        int base LOCALE_PARAM_PROTO)
Packit Service fdd496
{
Packit Service fdd496
  return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
Packit Service fdd496
}