source: trunk/third/gettext/lib/strtol.c @ 16931

Revision 16931, 12.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16930, which included commits to RCS files with non-trunk default branches.
Line 
1/* Convert string representation of a number into an integer value.
2   Copyright (C) 1991,92,94,95,96,97,98,99,2000 Free Software Foundation, Inc.
3
4   NOTE: The canonical source of this file is maintained with the GNU C Library.
5   Bugs can be reported to bug-glibc@gnu.org.
6
7   This program is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2, or (at your option) any
10   later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20   USA.  */
21
22#if HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26#ifdef _LIBC
27# define USE_NUMBER_GROUPING
28# define STDC_HEADERS
29# define HAVE_LIMITS_H
30#endif
31
32#include <ctype.h>
33#include <errno.h>
34#ifndef errno
35extern int errno;
36#endif
37#ifndef __set_errno
38# define __set_errno(Val) errno = (Val)
39#endif
40
41#ifdef HAVE_LIMITS_H
42# include <limits.h>
43#endif
44
45#ifdef STDC_HEADERS
46# include <stddef.h>
47# include <stdlib.h>
48# include <string.h>
49#else
50# ifndef NULL
51#  define NULL 0
52# endif
53#endif
54
55#ifdef USE_NUMBER_GROUPING
56# include "../locale/localeinfo.h"
57#endif
58
59/* Nonzero if we are defining `strtoul' or `strtoull', operating on
60   unsigned integers.  */
61#ifndef UNSIGNED
62# define UNSIGNED 0
63# define INT LONG int
64#else
65# define INT unsigned LONG int
66#endif
67
68/* Determine the name.  */
69#ifdef USE_IN_EXTENDED_LOCALE_MODEL
70# if UNSIGNED
71#  ifdef USE_WIDE_CHAR
72#   ifdef QUAD
73#    define strtol __wcstoull_l
74#   else
75#    define strtol __wcstoul_l
76#   endif
77#  else
78#   ifdef QUAD
79#    define strtol __strtoull_l
80#   else
81#    define strtol __strtoul_l
82#   endif
83#  endif
84# else
85#  ifdef USE_WIDE_CHAR
86#   ifdef QUAD
87#    define strtol __wcstoll_l
88#   else
89#    define strtol __wcstol_l
90#   endif
91#  else
92#   ifdef QUAD
93#    define strtol __strtoll_l
94#   else
95#    define strtol __strtol_l
96#   endif
97#  endif
98# endif
99#else
100# if UNSIGNED
101#  ifdef USE_WIDE_CHAR
102#   ifdef QUAD
103#    define strtol wcstoull
104#   else
105#    define strtol wcstoul
106#   endif
107#  else
108#   ifdef QUAD
109#    define strtol strtoull
110#   else
111#    define strtol strtoul
112#   endif
113#  endif
114# else
115#  ifdef USE_WIDE_CHAR
116#   ifdef QUAD
117#    define strtol wcstoll
118#   else
119#    define strtol wcstol
120#   endif
121#  else
122#   ifdef QUAD
123#    define strtol strtoll
124#   endif
125#  endif
126# endif
127#endif
128
129/* If QUAD is defined, we are defining `strtoll' or `strtoull',
130   operating on `long long int's.  */
131#ifdef QUAD
132# define LONG long long
133# define STRTOL_LONG_MIN LONG_LONG_MIN
134# define STRTOL_LONG_MAX LONG_LONG_MAX
135# define STRTOL_ULONG_MAX ULONG_LONG_MAX
136# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
137   /* Work around gcc bug with using this constant.  */
138   static const unsigned long long int maxquad = ULONG_LONG_MAX;
139#  undef STRTOL_ULONG_MAX
140#  define STRTOL_ULONG_MAX maxquad
141# endif
142#else
143# define LONG long
144
145# ifndef ULONG_MAX
146#  define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
147# endif
148# ifndef LONG_MAX
149#  define LONG_MAX ((long int) (ULONG_MAX >> 1))
150# endif
151# define STRTOL_LONG_MIN LONG_MIN
152# define STRTOL_LONG_MAX LONG_MAX
153# define STRTOL_ULONG_MAX ULONG_MAX
154#endif
155
156
157/* We use this code also for the extended locale handling where the
158   function gets as an additional argument the locale which has to be
159   used.  To access the values we have to redefine the _NL_CURRENT
160   macro.  */
161#ifdef USE_IN_EXTENDED_LOCALE_MODEL
162# undef _NL_CURRENT
163# define _NL_CURRENT(category, item) \
164  (current->values[_NL_ITEM_INDEX (item)].string)
165# define LOCALE_PARAM , loc
166# define LOCALE_PARAM_DECL __locale_t loc;
167#else
168# define LOCALE_PARAM
169# define LOCALE_PARAM_DECL
170#endif
171
172#if defined _LIBC || defined HAVE_WCHAR_H
173# include <wchar.h>
174#endif
175
176#ifdef USE_WIDE_CHAR
177# include <wctype.h>
178# define L_(Ch) L##Ch
179# define UCHAR_TYPE wint_t
180# define STRING_TYPE wchar_t
181# ifdef USE_IN_EXTENDED_LOCALE_MODEL
182#  define ISSPACE(Ch) __iswspace_l ((Ch), loc)
183#  define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
184#  define TOUPPER(Ch) __towupper_l ((Ch), loc)
185# else
186#  define ISSPACE(Ch) iswspace (Ch)
187#  define ISALPHA(Ch) iswalpha (Ch)
188#  define TOUPPER(Ch) towupper (Ch)
189# endif
190# else
191#  if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
192#   define IN_CTYPE_DOMAIN(c) 1
193#  else
194#   define IN_CTYPE_DOMAIN(c) isascii(c)
195#  endif
196#  define L_(Ch) Ch
197#  define UCHAR_TYPE unsigned char
198#  define STRING_TYPE char
199# ifdef USE_IN_EXTENDED_LOCALE_MODEL
200#  define ISSPACE(Ch) __isspace_l ((Ch), loc)
201#  define ISALPHA(Ch) __isalpha_l ((Ch), loc)
202#  define TOUPPER(Ch) __toupper_l ((Ch), loc)
203# else
204#  define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch))
205#  define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch))
206#  define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch))
207# endif
208#endif
209
210#ifdef __STDC__
211# define INTERNAL(X) INTERNAL1(X)
212# define INTERNAL1(X) __##X##_internal
213# define WEAKNAME(X) WEAKNAME1(X)
214#else
215# define INTERNAL(X) __/**/X/**/_internal
216#endif
217
218#ifdef USE_NUMBER_GROUPING
219/* This file defines a function to check for correct grouping.  */
220# include "grouping.h"
221#endif
222
223
224
225/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
226   If BASE is 0 the base is determined by the presence of a leading
227   zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
228   If BASE is < 2 or > 36, it is reset to 10.
229   If ENDPTR is not NULL, a pointer to the character after the last
230   one converted is stored in *ENDPTR.  */
231
232INT
233INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
234     const STRING_TYPE *nptr;
235     STRING_TYPE **endptr;
236     int base;
237     int group;
238     LOCALE_PARAM_DECL
239{
240  int negative;
241  register unsigned LONG int cutoff;
242  register unsigned int cutlim;
243  register unsigned LONG int i;
244  register const STRING_TYPE *s;
245  register UCHAR_TYPE c;
246  const STRING_TYPE *save, *end;
247  int overflow;
248#if defined USE_NUMBER_GROUPING && !defined USE_WIDE_CHAR
249  int cnt;
250#endif
251
252#ifdef USE_NUMBER_GROUPING
253# ifdef USE_IN_EXTENDED_LOCALE_MODEL
254  struct locale_data *current = loc->__locales[LC_NUMERIC];
255# endif
256  /* The thousands character of the current locale.  */
257# ifdef USE_WIDE_CHAR
258  wchar_t thousands = L'\0';
259# else
260  const char *thousands = NULL;
261  size_t thousands_len = 0;
262# endif
263  /* The numeric grouping specification of the current locale,
264     in the format described in <locale.h>.  */
265  const char *grouping;
266
267  if (group)
268    {
269      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
270      if (*grouping <= 0 || *grouping == CHAR_MAX)
271        grouping = NULL;
272      else
273        {
274          /* Figure out the thousands separator character.  */
275# ifdef USE_WIDE_CHAR
276#  ifdef _LIBC
277          thousands = _NL_CURRENT_WORD (LC_NUMERIC,
278                                        _NL_NUMERIC_THOUSANDS_SEP_WC);
279#  endif
280          if (thousands == L'\0')
281            grouping = NULL;
282# else
283#  ifdef _LIBC
284          thousands = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
285#  endif
286          if (*thousands == '\0')
287            {
288              thousands = NULL;
289              grouping = NULL;
290            }
291# endif
292        }
293    }
294  else
295    grouping = NULL;
296#endif
297
298  if (base < 0 || base == 1 || base > 36)
299    {
300      __set_errno (EINVAL);
301      return 0;
302    }
303
304  save = s = nptr;
305
306  /* Skip white space.  */
307  while (ISSPACE (*s))
308    ++s;
309  if (*s == L_('\0'))
310    goto noconv;
311
312  /* Check for a sign.  */
313  if (*s == L_('-'))
314    {
315      negative = 1;
316      ++s;
317    }
318  else if (*s == L_('+'))
319    {
320      negative = 0;
321      ++s;
322    }
323  else
324    negative = 0;
325
326  /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
327  if (*s == L_('0'))
328    {
329      if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
330        {
331          s += 2;
332          base = 16;
333        }
334      else if (base == 0)
335        base = 8;
336    }
337  else if (base == 0)
338    base = 10;
339
340  /* Save the pointer so we can check later if anything happened.  */
341  save = s;
342
343#ifdef USE_NUMBER_GROUPING
344  if (base != 10)
345    grouping = NULL;
346
347  if (grouping)
348    {
349# ifndef USE_WIDE_CHAR
350      thousands_len = strlen (thousands);
351# endif
352
353      /* Find the end of the digit string and check its grouping.  */
354      end = s;
355      if (
356# ifdef USE_WIDE_CHAR
357          *s != thousands
358# else
359          ({ for (cnt = 0; cnt < thousands_len; ++cnt)
360               if (thousands[cnt] != end[cnt])
361                 break;
362             cnt < thousands_len; })
363# endif
364          )
365        {
366          for (c = *end; c != L_('\0'); c = *++end)
367            if (((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
368# ifdef USE_WIDE_CHAR
369                && c != thousands
370# else
371                && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
372                      if (thousands[cnt] != end[cnt])
373                        break;
374                      cnt < thousands_len; })
375# endif
376                && (!ISALPHA (c)
377                    || (int) (TOUPPER (c) - L_('A') + 10) >= base))
378              break;
379
380          end = correctly_grouped_prefix (s, end, thousands, grouping);
381        }
382    }
383  else
384#endif
385    end = NULL;
386
387  cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
388  cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
389
390  overflow = 0;
391  i = 0;
392  c = *s;
393  if (sizeof (long int) != sizeof (LONG int))
394    {
395      unsigned long int j = 0;
396      unsigned long int jmax = ULONG_MAX / base;
397
398      for (;c != L_('\0'); c = *++s)
399        {
400          if (s == end)
401            break;
402          if (c >= L_('0') && c <= L_('9'))
403            c -= L_('0');
404#ifdef USE_NUMBER_GROUPING
405# ifdef USE_WIDE_CHAR
406          else if (grouping && c == thousands)
407            continue;
408# else
409          else if (thousands_len)
410            {
411              for (cnt = 0; cnt < thousands_len; ++cnt)
412                if (thousands[cnt] != s[cnt])
413                  break;
414              if (cnt == thousands_len)
415                {
416                  s += thousands_len - 1;
417                  continue;
418                }
419              if (ISALPHA (c))
420                c = TOUPPER (c) - L_('A') + 10;
421              else
422                break;
423            }
424# endif
425#endif
426          else if (ISALPHA (c))
427            c = TOUPPER (c) - L_('A') + 10;
428          else
429            break;
430          if ((int) c >= base)
431            break;
432          /* Note that we never can have an overflow.  */
433          else if (j >= jmax)
434            {
435              /* We have an overflow.  Now use the long representation.  */
436              i = (unsigned LONG int) j;
437              goto use_long;
438            }
439          else
440            j = j * (unsigned long int) base + c;
441        }
442
443      i = (unsigned LONG int) j;
444    }
445  else
446    for (;c != L_('\0'); c = *++s)
447      {
448        if (s == end)
449          break;
450        if (c >= L_('0') && c <= L_('9'))
451          c -= L_('0');
452#ifdef USE_NUMBER_GROUPING
453# ifdef USE_WIDE_CHAR
454        else if (grouping && c == thousands)
455          continue;
456# else
457        else if (thousands_len)
458          {
459            for (cnt = 0; cnt < thousands_len; ++cnt)
460              if (thousands[cnt] != s[cnt])
461                break;
462            if (cnt == thousands_len)
463              {
464                s += thousands_len - 1;
465                continue;
466              }
467            if (ISALPHA (c))
468              c = TOUPPER (c) - L_('A') + 10;
469            else
470              break;
471          }
472# endif
473#endif
474        else if (ISALPHA (c))
475          c = TOUPPER (c) - L_('A') + 10;
476        else
477          break;
478        if ((int) c >= base)
479          break;
480        /* Check for overflow.  */
481        if (i > cutoff || (i == cutoff && c > cutlim))
482          overflow = 1;
483        else
484          {
485          use_long:
486            i *= (unsigned LONG int) base;
487            i += c;
488          }
489      }
490
491  /* Check if anything actually happened.  */
492  if (s == save)
493    goto noconv;
494
495  /* Store in ENDPTR the address of one character
496     past the last character we converted.  */
497  if (endptr != NULL)
498    *endptr = (STRING_TYPE *) s;
499
500#if !UNSIGNED
501  /* Check for a value that is within the range of
502     `unsigned LONG int', but outside the range of `LONG int'.  */
503  if (overflow == 0
504      && i > (negative
505              ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
506              : (unsigned LONG int) STRTOL_LONG_MAX))
507    overflow = 1;
508#endif
509
510  if (overflow)
511    {
512      __set_errno (ERANGE);
513#if UNSIGNED
514      return STRTOL_ULONG_MAX;
515#else
516      return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
517#endif
518    }
519
520  /* Return the result of the appropriate sign.  */
521  return negative ? -i : i;
522
523noconv:
524  /* We must handle a special case here: the base is 0 or 16 and the
525     first two characters are '0' and 'x', but the rest are no
526     hexadecimal digits.  This is no error case.  We return 0 and
527     ENDPTR points to the `x`.  */
528  if (endptr != NULL)
529    {
530      if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
531          && save[-2] == L_('0'))
532        *endptr = (STRING_TYPE *) &save[-1];
533      else
534        /*  There was no number to convert.  */
535        *endptr = (STRING_TYPE *) nptr;
536    }
537
538  return 0L;
539}
540
541/* External user entry point.  */
542
543#if _LIBC - 0 == 0
544# undef PARAMS
545# if defined (__STDC__) && __STDC__
546#  define PARAMS(Args) Args
547# else
548#  define PARAMS(Args) ()
549# endif
550
551/* Prototype.  */
552INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
553#endif
554
555
556INT
557#ifdef weak_function
558weak_function
559#endif
560strtol (nptr, endptr, base LOCALE_PARAM)
561     const STRING_TYPE *nptr;
562     STRING_TYPE **endptr;
563     int base;
564     LOCALE_PARAM_DECL
565{
566  return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
567}
Note: See TracBrowser for help on using the repository browser.