Blame lib/strtol.c

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