root/maint/gnulib/lib/strtol.c

/* [previous][next][first][last][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-2021 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)
 292         base = 8;
 293     }
 294   else if (base == 0)
 295     base = 10;
 296 
 297   /* Save the pointer so we can check later if anything happened.  */
 298   save = s;
 299 
 300 #ifdef USE_NUMBER_GROUPING
 301   if (group)
 302     {
 303       /* Find the end of the digit string and check its grouping.  */
 304       end = s;
 305       for (c = *end; c != L_('\0'); c = *++end)
 306         if ((wchar_t) c != thousands
 307             && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
 308             && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
 309           break;
 310       if (*s == thousands)
 311         end = s;
 312       else
 313         end = correctly_grouped_prefix (s, end, thousands, grouping);
 314     }
 315   else
 316 #endif
 317     end = NULL;
 318 
 319   cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
 320   cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
 321 
 322   overflow = 0;
 323   i = 0;
 324   for (c = *s; c != L_('\0'); c = *++s)
 325     {
 326       if (s == end)
 327         break;
 328       if (c >= L_('0') && c <= L_('9'))
 329         c -= L_('0');
 330       else if (ISALPHA (c))
 331         c = TOUPPER (c) - L_('A') + 10;
 332       else
 333         break;
 334       if ((int) c >= base)
 335         break;
 336       /* Check for overflow.  */
 337       if (i > cutoff || (i == cutoff && c > cutlim))
 338         overflow = 1;
 339       else
 340         {
 341           i *= (unsigned LONG int) base;
 342           i += c;
 343         }
 344     }
 345 
 346   /* Check if anything actually happened.  */
 347   if (s == save)
 348     goto noconv;
 349 
 350   /* Store in ENDPTR the address of one character
 351      past the last character we converted.  */
 352   if (endptr != NULL)
 353     *endptr = (STRING_TYPE *) s;
 354 
 355 #if !UNSIGNED
 356   /* Check for a value that is within the range of
 357      'unsigned LONG int', but outside the range of 'LONG int'.  */
 358   if (overflow == 0
 359       && i > (negative
 360               ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
 361               : (unsigned LONG int) STRTOL_LONG_MAX))
 362     overflow = 1;
 363 #endif
 364 
 365   if (overflow)
 366     {
 367       __set_errno (ERANGE);
 368 #if UNSIGNED
 369       return STRTOL_ULONG_MAX;
 370 #else
 371       return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
 372 #endif
 373     }
 374 
 375   /* Return the result of the appropriate sign.  */
 376   return negative ? -i : i;
 377 
 378 noconv:
 379   /* We must handle a special case here: the base is 0 or 16 and the
 380      first two characters are '0' and 'x', but the rest are no
 381      hexadecimal digits.  This is no error case.  We return 0 and
 382      ENDPTR points to the 'x'.  */
 383   if (endptr != NULL)
 384     {
 385       if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
 386           && save[-2] == L_('0'))
 387         *endptr = (STRING_TYPE *) &save[-1];
 388       else
 389         /*  There was no number to convert.  */
 390         *endptr = (STRING_TYPE *) nptr;
 391     }
 392 
 393   return 0L;
 394 }
 395 
 396 #ifdef USE_NUMBER_GROUPING
 397 /* External user entry point.  */
 398 
 399 INT
 400 # ifdef weak_function
 401 weak_function
 402 # endif
 403 strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 404         int base LOCALE_PARAM_PROTO)
 405 {
 406   return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
 407 }
 408 #endif

/* [previous][next][first][last][top][bottom][index][help] */