root/lib/strtol.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. strtol

     1 /* Convert string representation of a number into an integer value.
     2 
     3    Copyright (C) 1991-1992, 1994-1999, 2003, 2005-2007, 2009-2023 Free Software
     4    Foundation, Inc.
     5 
     6    NOTE: The canonical source of this file is maintained with the GNU C
     7    Library.  Bugs can be reported to bug-glibc@gnu.org.
     8 
     9    This file is free software: you can redistribute it and/or modify
    10    it under the terms of the GNU Lesser General Public License as
    11    published by the Free Software Foundation, either version 3 of the
    12    License, or (at your option) any later version.
    13 
    14    This file is distributed in the hope that it will be useful,
    15    but WITHOUT ANY WARRANTY; without even the implied warranty of
    16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17    GNU Lesser General Public License for more details.
    18 
    19    You should have received a copy of the GNU Lesser General Public License
    20    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    21 
    22 #ifdef _LIBC
    23 # define USE_NUMBER_GROUPING
    24 #else
    25 # include <config.h>
    26 #endif
    27 
    28 #include <ctype.h>
    29 #include <errno.h>
    30 #ifndef __set_errno
    31 # define __set_errno(Val) errno = (Val)
    32 #endif
    33 
    34 #include <limits.h>
    35 #include <stddef.h>
    36 #include <stdlib.h>
    37 #include <string.h>
    38 
    39 #ifdef USE_NUMBER_GROUPING
    40 # include "../locale/localeinfo.h"
    41 #endif
    42 
    43 /* Nonzero if we are defining 'strtoul' or 'strtoull', operating on
    44    unsigned integers.  */
    45 #ifndef UNSIGNED
    46 # define UNSIGNED 0
    47 # define INT LONG int
    48 #else
    49 # define INT unsigned LONG int
    50 #endif
    51 
    52 /* Determine the name.  */
    53 #ifdef USE_IN_EXTENDED_LOCALE_MODEL
    54 # undef strtol
    55 # if UNSIGNED
    56 #  ifdef USE_WIDE_CHAR
    57 #   ifdef QUAD
    58 #    define strtol __wcstoull_l
    59 #   else
    60 #    define strtol __wcstoul_l
    61 #   endif
    62 #  else
    63 #   ifdef QUAD
    64 #    define strtol __strtoull_l
    65 #   else
    66 #    define strtol __strtoul_l
    67 #   endif
    68 #  endif
    69 # else
    70 #  ifdef USE_WIDE_CHAR
    71 #   ifdef QUAD
    72 #    define strtol __wcstoll_l
    73 #   else
    74 #    define strtol __wcstol_l
    75 #   endif
    76 #  else
    77 #   ifdef QUAD
    78 #    define strtol __strtoll_l
    79 #   else
    80 #    define strtol __strtol_l
    81 #   endif
    82 #  endif
    83 # endif
    84 #else
    85 # if UNSIGNED
    86 #  undef strtol
    87 #  ifdef USE_WIDE_CHAR
    88 #   ifdef QUAD
    89 #    define strtol wcstoull
    90 #   else
    91 #    define strtol wcstoul
    92 #   endif
    93 #  else
    94 #   ifdef QUAD
    95 #    define strtol strtoull
    96 #   else
    97 #    define strtol strtoul
    98 #   endif
    99 #  endif
   100 # else
   101 #  ifdef USE_WIDE_CHAR
   102 #   undef strtol
   103 #   ifdef QUAD
   104 #    define strtol wcstoll
   105 #   else
   106 #    define strtol wcstol
   107 #   endif
   108 #  else
   109 #   ifdef QUAD
   110 #    undef strtol
   111 #    define strtol strtoll
   112 #   endif
   113 #  endif
   114 # endif
   115 #endif
   116 
   117 /* If QUAD is defined, we are defining 'strtoll' or 'strtoull',
   118    operating on 'long long int's.  */
   119 #ifdef QUAD
   120 # define LONG long long
   121 # define STRTOL_LONG_MIN LLONG_MIN
   122 # define STRTOL_LONG_MAX LLONG_MAX
   123 # define STRTOL_ULONG_MAX ULLONG_MAX
   124 # if __GNUC__ == 2 && __GNUC_MINOR__ < 7
   125    /* Work around gcc bug with using this constant.  */
   126    static const unsigned long long int maxquad = ULLONG_MAX;
   127 #  undef STRTOL_ULONG_MAX
   128 #  define STRTOL_ULONG_MAX maxquad
   129 # endif
   130 #else
   131 # define LONG long
   132 # define STRTOL_LONG_MIN LONG_MIN
   133 # define STRTOL_LONG_MAX LONG_MAX
   134 # define STRTOL_ULONG_MAX ULONG_MAX
   135 #endif
   136 
   137 
   138 #ifdef USE_NUMBER_GROUPING
   139 # define GROUP_PARAM_PROTO , int group
   140 #else
   141 # define GROUP_PARAM_PROTO
   142 #endif
   143 
   144 /* We use this code also for the extended locale handling where the
   145    function gets as an additional argument the locale which has to be
   146    used.  To access the values we have to redefine the _NL_CURRENT
   147    macro.  */
   148 #ifdef USE_IN_EXTENDED_LOCALE_MODEL
   149 # undef _NL_CURRENT
   150 # define _NL_CURRENT(category, item) \
   151   (current->values[_NL_ITEM_INDEX (item)].string)
   152 # define LOCALE_PARAM , loc
   153 # define LOCALE_PARAM_PROTO , __locale_t loc
   154 #else
   155 # define LOCALE_PARAM
   156 # define LOCALE_PARAM_PROTO
   157 #endif
   158 
   159 #ifdef USE_WIDE_CHAR
   160 # include <wchar.h>
   161 # include <wctype.h>
   162 # define L_(Ch) L##Ch
   163 # define UCHAR_TYPE wint_t
   164 # define STRING_TYPE wchar_t
   165 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
   166 #  define ISSPACE(Ch) __iswspace_l ((Ch), loc)
   167 #  define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
   168 #  define TOUPPER(Ch) __towupper_l ((Ch), loc)
   169 # else
   170 #  define ISSPACE(Ch) iswspace (Ch)
   171 #  define ISALPHA(Ch) iswalpha (Ch)
   172 #  define TOUPPER(Ch) towupper (Ch)
   173 # endif
   174 #else
   175 # define L_(Ch) Ch
   176 # define UCHAR_TYPE unsigned char
   177 # define STRING_TYPE char
   178 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
   179 #  define ISSPACE(Ch) __isspace_l ((unsigned char) (Ch), loc)
   180 #  define ISALPHA(Ch) __isalpha_l ((unsigned char) (Ch), loc)
   181 #  define TOUPPER(Ch) __toupper_l ((unsigned char) (Ch), loc)
   182 # else
   183 #  define ISSPACE(Ch) isspace ((unsigned char) (Ch))
   184 #  define ISALPHA(Ch) isalpha ((unsigned char) (Ch))
   185 #  define TOUPPER(Ch) toupper ((unsigned char) (Ch))
   186 # endif
   187 #endif
   188 
   189 #ifdef USE_NUMBER_GROUPING
   190 # define INTERNAL(X) INTERNAL1(X)
   191 # define INTERNAL1(X) __##X##_internal
   192 # define WEAKNAME(X) WEAKNAME1(X)
   193 #else
   194 # define INTERNAL(X) X
   195 #endif
   196 
   197 #ifdef USE_NUMBER_GROUPING
   198 /* This file defines a function to check for correct grouping.  */
   199 # include "grouping.h"
   200 #endif
   201 
   202 
   203 
   204 /* Convert NPTR to an 'unsigned long int' or 'long int' in base BASE.
   205    If BASE is 0 the base is determined by the presence of a leading
   206    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
   207    If BASE is < 2 or > 36, it is reset to 10.
   208    If ENDPTR is not NULL, a pointer to the character after the last
   209    one converted is stored in *ENDPTR.  */
   210 
   211 INT
   212 INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
   213                    int base GROUP_PARAM_PROTO LOCALE_PARAM_PROTO)
   214 {
   215   int negative;
   216   register unsigned LONG int cutoff;
   217   register unsigned int cutlim;
   218   register unsigned LONG int i;
   219   register const STRING_TYPE *s;
   220   register UCHAR_TYPE c;
   221   const STRING_TYPE *save, *end;
   222   int overflow;
   223 
   224 #ifdef USE_NUMBER_GROUPING
   225 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
   226   struct locale_data *current = loc->__locales[LC_NUMERIC];
   227 # endif
   228   /* The thousands character of the current locale.  */
   229   wchar_t thousands = L'\0';
   230   /* The numeric grouping specification of the current locale,
   231      in the format described in <locale.h>.  */
   232   const char *grouping;
   233 
   234   if (group)
   235     {
   236       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
   237       if (*grouping <= 0 || *grouping == CHAR_MAX)
   238         grouping = NULL;
   239       else
   240         {
   241           /* Figure out the thousands separator character.  */
   242 # if defined _LIBC || defined _HAVE_BTOWC
   243           thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
   244           if (thousands == WEOF)
   245             thousands = L'\0';
   246 # endif
   247           if (thousands == L'\0')
   248             grouping = NULL;
   249         }
   250     }
   251   else
   252     grouping = NULL;
   253 #endif
   254 
   255   if (base < 0 || base == 1 || base > 36)
   256     {
   257       __set_errno (EINVAL);
   258       return 0;
   259     }
   260 
   261   save = s = nptr;
   262 
   263   /* Skip white space.  */
   264   while (ISSPACE (*s))
   265     ++s;
   266   if (*s == L_('\0'))
   267     goto noconv;
   268 
   269   /* Check for a sign.  */
   270   if (*s == L_('-'))
   271     {
   272       negative = 1;
   273       ++s;
   274     }
   275   else if (*s == L_('+'))
   276     {
   277       negative = 0;
   278       ++s;
   279     }
   280   else
   281     negative = 0;
   282 
   283   /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
   284   if (*s == L_('0'))
   285     {
   286       if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
   287         {
   288           s += 2;
   289           base = 16;
   290         }
   291       else if ((base == 0 || base == 2) && TOUPPER (s[1]) == L_('B'))
   292         {
   293           s += 2;
   294           base = 2;
   295         }
   296       else if (base == 0)
   297         base = 8;
   298     }
   299   else if (base == 0)
   300     base = 10;
   301 
   302   /* Save the pointer so we can check later if anything happened.  */
   303   save = s;
   304 
   305 #ifdef USE_NUMBER_GROUPING
   306   if (group)
   307     {
   308       /* Find the end of the digit string and check its grouping.  */
   309       end = s;
   310       for (c = *end; c != L_('\0'); c = *++end)
   311         if ((wchar_t) c != thousands
   312             && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
   313             && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
   314           break;
   315       if (*s == thousands)
   316         end = s;
   317       else
   318         end = correctly_grouped_prefix (s, end, thousands, grouping);
   319     }
   320   else
   321 #endif
   322     end = NULL;
   323 
   324   cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
   325   cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
   326 
   327   overflow = 0;
   328   i = 0;
   329   for (c = *s; c != L_('\0'); c = *++s)
   330     {
   331       if (s == end)
   332         break;
   333       if (c >= L_('0') && c <= L_('9'))
   334         c -= L_('0');
   335       else if (ISALPHA (c))
   336         c = TOUPPER (c) - L_('A') + 10;
   337       else
   338         break;
   339       if ((int) c >= base)
   340         break;
   341       /* Check for overflow.  */
   342       if (i > cutoff || (i == cutoff && c > cutlim))
   343         overflow = 1;
   344       else
   345         {
   346           i *= (unsigned LONG int) base;
   347           i += c;
   348         }
   349     }
   350 
   351   /* Check if anything actually happened.  */
   352   if (s == save)
   353     goto noconv;
   354 
   355   /* Store in ENDPTR the address of one character
   356      past the last character we converted.  */
   357   if (endptr != NULL)
   358     *endptr = (STRING_TYPE *) s;
   359 
   360 #if !UNSIGNED
   361   /* Check for a value that is within the range of
   362      'unsigned LONG int', but outside the range of 'LONG int'.  */
   363   if (overflow == 0
   364       && i > (negative
   365               ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
   366               : (unsigned LONG int) STRTOL_LONG_MAX))
   367     overflow = 1;
   368 #endif
   369 
   370   if (overflow)
   371     {
   372       __set_errno (ERANGE);
   373 #if UNSIGNED
   374       return STRTOL_ULONG_MAX;
   375 #else
   376       return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
   377 #endif
   378     }
   379 
   380   /* Return the result of the appropriate sign.  */
   381   return negative ? -i : i;
   382 
   383 noconv:
   384   /* We must handle a special case here: the base is 0 or 16 and the
   385      first two characters are '0' and 'x', but the rest are no
   386      hexadecimal digits.  Likewise when the base is 0 or 2 and the
   387      first two characters are '0' and 'b', but the rest are no binary
   388      digits.  This is no error case.  We return 0 and ENDPTR points to
   389      the 'x' or 'b'.  */
   390   if (endptr != NULL)
   391     {
   392       if (save - nptr >= 2
   393           && (TOUPPER (save[-1]) == L_('X') || TOUPPER (save[-1]) == L_('B'))
   394           && save[-2] == L_('0'))
   395         *endptr = (STRING_TYPE *) &save[-1];
   396       else
   397         /*  There was no number to convert.  */
   398         *endptr = (STRING_TYPE *) nptr;
   399     }
   400 
   401   return 0L;
   402 }
   403 
   404 #ifdef USE_NUMBER_GROUPING
   405 /* External user entry point.  */
   406 
   407 INT
   408 # ifdef weak_function
   409 weak_function
   410 # endif
   411 strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr,
   412         int base LOCALE_PARAM_PROTO)
   413 {
   414   return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
   415 }
   416 #endif

/* [<][>][^][v][top][bottom][index][help] */