Back to index

tetex-bin  3.0
strtol.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
00002 
00003 This file is part of the GNU C Library.
00004 
00005 The GNU C Library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Library General Public License as
00007 published by the Free Software Foundation; either version 2 of the
00008 License, or (at your option) any later version.
00009 
00010 The GNU C Library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Library General Public License for more details.
00014 
00015 You should have received a copy of the GNU Library General Public
00016 License along with the GNU C Library; see the file COPYING.LIB.  If
00017 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
00018 Cambridge, MA 02139, USA.  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023 
00024 #ifdef _LIBC
00025 # define USE_NUMBER_GROUPING
00026 # define STDC_HEADERS
00027 # define HAVE_LIMITS_H
00028 #endif
00029 
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #ifndef errno
00033 extern int errno;
00034 #endif
00035 
00036 #ifdef HAVE_LIMITS_H
00037 # include <limits.h>
00038 #endif
00039 
00040 #ifdef STDC_HEADERS
00041 # include <stddef.h>
00042 # include <stdlib.h>
00043 #else
00044 # ifndef NULL
00045 #  define NULL 0
00046 # endif
00047 #endif
00048 
00049 #ifdef USE_NUMBER_GROUPING
00050 # include "../locale/localeinfo.h"
00051 #endif
00052 
00053 /* Nonzero if we are defining `strtoul' or `strtouq', operating on
00054    unsigned integers.  */
00055 #ifndef UNSIGNED
00056 # define UNSIGNED 0
00057 # define INT LONG int
00058 #else
00059 # define strtol strtoul
00060 # define INT unsigned LONG int
00061 #endif
00062 
00063 /* If QUAD is defined, we are defining `strtoq' or `strtouq',
00064    operating on `long long int's.  */
00065 #ifdef QUAD
00066 # if UNSIGNED
00067 #  define strtoul strtouq
00068 # else
00069 #  define strtol strtoq
00070 # endif
00071 # define LONG long long
00072 # undef LONG_MIN
00073 # define LONG_MIN LONG_LONG_MIN
00074 # undef LONG_MAX
00075 # define LONG_MAX LONG_LONG_MAX
00076 # undef ULONG_MAX
00077 # define ULONG_MAX ULONG_LONG_MAX
00078 # if __GNUC__ == 2 && __GNUC_MINOR__ < 7
00079    /* Work around gcc bug with using this constant.  */
00080    static const unsigned long long int maxquad = ULONG_LONG_MAX;
00081 #  undef ULONG_MAX
00082 #  define ULONG_MAX maxquad
00083 # endif
00084 #else
00085 # define LONG long
00086 #endif
00087 
00088 #ifdef __STDC__
00089 # define INTERNAL(x) INTERNAL1(x)
00090 # define INTERNAL1(x) __##x##_internal
00091 #else
00092 # define INTERNAL(x) __x_internal
00093 #endif
00094 
00095 #ifdef USE_NUMBER_GROUPING
00096 /* This file defines a function to check for correct grouping.  */
00097 # include "grouping.h"
00098 #endif
00099 
00100 
00101 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
00102    If BASE is 0 the base is determined by the presence of a leading
00103    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
00104    If BASE is < 2 or > 36, it is reset to 10.
00105    If ENDPTR is not NULL, a pointer to the character after the last
00106    one converted is stored in *ENDPTR.  */
00107 
00108 INT
00109 INTERNAL (strtol) (nptr, endptr, base, group)
00110      const char *nptr;
00111      char **endptr;
00112      int base;
00113      int group;
00114 {
00115   int negative;
00116   register unsigned LONG int cutoff;
00117   register unsigned int cutlim;
00118   register unsigned LONG int i;
00119   register const char *s;
00120   register unsigned char c;
00121   const char *save, *end;
00122   int overflow;
00123 
00124 #ifdef USE_NUMBER_GROUPING
00125   /* The thousands character of the current locale.  */
00126   wchar_t thousands;
00127   /* The numeric grouping specification of the current locale,
00128      in the format described in <locale.h>.  */
00129   const char *grouping;
00130 
00131   if (group)
00132     {
00133       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
00134       if (*grouping <= 0 || *grouping == CHAR_MAX)
00135        grouping = NULL;
00136       else
00137        {
00138          /* Figure out the thousands separator character.  */
00139          if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
00140                     strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
00141            thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
00142          if (thousands == L'\0')
00143            grouping = NULL;
00144        }
00145     }
00146   else
00147     grouping = NULL;
00148 #endif
00149 
00150   if (base < 0 || base == 1 || base > 36)
00151     base = 10;
00152 
00153   s = nptr;
00154 
00155   /* Skip white space.  */
00156   while (isspace (*s))
00157     ++s;
00158   if (*s == '\0')
00159     goto noconv;
00160 
00161   /* Check for a sign.  */
00162   if (*s == '-')
00163     {
00164       negative = 1;
00165       ++s;
00166     }
00167   else if (*s == '+')
00168     {
00169       negative = 0;
00170       ++s;
00171     }
00172   else
00173     negative = 0;
00174 
00175   if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
00176     s += 2;
00177 
00178   /* If BASE is zero, figure it out ourselves.  */
00179   if (base == 0)
00180     if (*s == '0')
00181       {
00182        if (toupper (s[1]) == 'X')
00183          {
00184            s += 2;
00185            base = 16;
00186          }
00187        else
00188          base = 8;
00189       }
00190     else
00191       base = 10;
00192 
00193   /* Save the pointer so we can check later if anything happened.  */
00194   save = s;
00195 
00196 #ifdef USE_NUMBER_GROUPING
00197   if (group)
00198     {
00199       /* Find the end of the digit string and check its grouping.  */
00200       end = s;
00201       for (c = *end; c != '\0'; c = *++end)
00202        if (c != thousands && !isdigit (c) &&
00203            (!isalpha (c) || toupper (c) - 'A' + 10 >= base))
00204          break;
00205       if (*s == thousands)
00206        end = s;
00207       else
00208        end = correctly_grouped_prefix (s, end, thousands, grouping);
00209     }
00210   else
00211 #endif
00212     end = NULL;
00213 
00214   cutoff = ULONG_MAX / (unsigned LONG int) base;
00215   cutlim = ULONG_MAX % (unsigned LONG int) base;
00216 
00217   overflow = 0;
00218   i = 0;
00219   for (c = *s; c != '\0'; c = *++s)
00220     {
00221       if (s == end)
00222        break;
00223       if (isdigit (c))
00224        c -= '0';
00225       else if (isalpha (c))
00226        c = toupper (c) - 'A' + 10;
00227       else
00228        break;
00229       if (c >= base)
00230        break;
00231       /* Check for overflow.  */
00232       if (i > cutoff || (i == cutoff && c > cutlim))
00233        overflow = 1;
00234       else
00235        {
00236          i *= (unsigned LONG int) base;
00237          i += c;
00238        }
00239     }
00240 
00241   /* Check if anything actually happened.  */
00242   if (s == save)
00243     goto noconv;
00244 
00245   /* Store in ENDPTR the address of one character
00246      past the last character we converted.  */
00247   if (endptr != NULL)
00248     *endptr = (char *) s;
00249 
00250 #if !UNSIGNED
00251   /* Check for a value that is within the range of
00252      `unsigned LONG int', but outside the range of `LONG int'.  */
00253   if (i > (negative ?
00254           -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX))
00255     overflow = 1;
00256 #endif
00257 
00258   if (overflow)
00259     {
00260       errno = ERANGE;
00261 #if UNSIGNED
00262       return ULONG_MAX;
00263 #else
00264       return negative ? LONG_MIN : LONG_MAX;
00265 #endif
00266     }
00267 
00268   /* Return the result of the appropriate sign.  */
00269   return (negative ? -i : i);
00270 
00271 noconv:
00272   /* There was no number to convert.  */
00273   if (endptr != NULL)
00274     *endptr = (char *) nptr;
00275   return 0L;
00276 }
00277 
00278 /* External user entry point.  */
00279 
00280 #ifdef weak_symbol
00281 weak_symbol (strtol)
00282 #endif
00283 
00284 INT
00285 strtol (nptr, endptr, base)
00286      const char *nptr;
00287      char **endptr;
00288      int base;
00289 {
00290   return INTERNAL (strtol) (nptr, endptr, base, 0);
00291 }