dvitomp fix from Akira
[mplib] / src / texk / kpathsea / strtol.c
1 /* strtol.c - convert a string to an unsigned long int.
2
3    Copyright 1997, 2008 Karl Berry.
4    Copyright 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
5    Modified by Karl Berry for kpathsea.
6
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    This library 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 GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public License
18    along with this library; if not, see <http://www.gnu.org/licenses/>.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #ifdef _LIBC
25 # define USE_NUMBER_GROUPING
26 # define STDC_HEADERS
27 # define HAVE_LIMITS_H
28 #endif
29
30 #include <ctype.h>
31 #include <errno.h>
32 #ifndef errno
33 extern int errno;
34 #endif
35
36 #ifdef HAVE_LIMITS_H
37 # include <limits.h>
38 #endif
39
40 #ifdef STDC_HEADERS
41 # include <stddef.h>
42 # include <stdlib.h>
43 #else
44 # ifndef NULL
45 #  define NULL 0
46 # endif
47 #endif
48
49 #ifdef USE_NUMBER_GROUPING
50 # include "../locale/localeinfo.h"
51 #endif
52
53 /* Nonzero if we are defining `strtoul' or `strtouq', operating on
54    unsigned integers.  */
55 #ifndef UNSIGNED
56 # define UNSIGNED 0
57 # define INT LONG int
58 #else
59 # define strtol strtoul
60 # define INT unsigned LONG int
61 #endif
62
63 /* If QUAD is defined, we are defining `strtoq' or `strtouq',
64    operating on `long long int's.  */
65 #ifdef QUAD
66 # if UNSIGNED
67 #  define strtoul strtouq
68 # else
69 #  define strtol strtoq
70 # endif
71 # define LONG long long
72 # undef LONG_MIN
73 # define LONG_MIN LONG_LONG_MIN
74 # undef LONG_MAX
75 # define LONG_MAX LONG_LONG_MAX
76 # undef ULONG_MAX
77 # define ULONG_MAX ULONG_LONG_MAX
78 # if __GNUC__ == 2 && __GNUC_MINOR__ < 7
79    /* Work around gcc bug with using this constant.  */
80    static const unsigned long long int maxquad = ULONG_LONG_MAX;
81 #  undef ULONG_MAX
82 #  define ULONG_MAX maxquad
83 # endif
84 #else
85 # define LONG long
86 #endif
87
88 #ifdef __STDC__
89 # define INTERNAL(x) INTERNAL1(x)
90 # define INTERNAL1(x) __##x##_internal
91 #else
92 # define INTERNAL(x) __/**/x/**/_internal
93 #endif
94
95 #ifdef USE_NUMBER_GROUPING
96 /* This file defines a function to check for correct grouping.  */
97 # include "grouping.h"
98 #endif
99
100
101 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
102    If BASE is 0 the base is determined by the presence of a leading
103    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
104    If BASE is < 2 or > 36, it is reset to 10.
105    If ENDPTR is not NULL, a pointer to the character after the last
106    one converted is stored in *ENDPTR.  */
107
108 INT
109 INTERNAL (strtol) (nptr, endptr, base, group)
110      const char *nptr;
111      char **endptr;
112      int base;
113      int group;
114 {
115   int negative;
116   register unsigned LONG int cutoff;
117   register unsigned int cutlim;
118   register unsigned LONG int i;
119   register const char *s;
120   register unsigned char c;
121   const char *save, *end;
122   int overflow;
123
124 #ifdef USE_NUMBER_GROUPING
125   /* The thousands character of the current locale.  */
126   wchar_t thousands;
127   /* The numeric grouping specification of the current locale,
128      in the format described in <locale.h>.  */
129   const char *grouping;
130
131   if (group)
132     {
133       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
134       if (*grouping <= 0 || *grouping == CHAR_MAX)
135         grouping = NULL;
136       else
137         {
138           /* Figure out the thousands separator character.  */
139           if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
140                       strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
141             thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
142           if (thousands == L'\0')
143             grouping = NULL;
144         }
145     }
146   else
147     grouping = NULL;
148 #endif
149
150   if (base < 0 || base == 1 || base > 36)
151     base = 10;
152
153   s = nptr;
154
155   /* Skip white space.  */
156   while (isspace (*s))
157     ++s;
158   if (*s == '\0')
159     goto noconv;
160
161   /* Check for a sign.  */
162   if (*s == '-')
163     {
164       negative = 1;
165       ++s;
166     }
167   else if (*s == '+')
168     {
169       negative = 0;
170       ++s;
171     }
172   else
173     negative = 0;
174
175   if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
176     s += 2;
177
178   /* If BASE is zero, figure it out ourselves.  */
179   if (base == 0)
180     if (*s == '0')
181       {
182         if (toupper (s[1]) == 'X')
183           {
184             s += 2;
185             base = 16;
186           }
187         else
188           base = 8;
189       }
190     else
191       base = 10;
192
193   /* Save the pointer so we can check later if anything happened.  */
194   save = s;
195
196 #ifdef USE_NUMBER_GROUPING
197   if (group)
198     {
199       /* Find the end of the digit string and check its grouping.  */
200       end = s;
201       for (c = *end; c != '\0'; c = *++end)
202         if (c != thousands && !isdigit (c) &&
203             (!isalpha (c) || toupper (c) - 'A' + 10 >= base))
204           break;
205       if (*s == thousands)
206         end = s;
207       else
208         end = correctly_grouped_prefix (s, end, thousands, grouping);
209     }
210   else
211 #endif
212     end = NULL;
213
214   cutoff = ULONG_MAX / (unsigned LONG int) base;
215   cutlim = ULONG_MAX % (unsigned LONG int) base;
216
217   overflow = 0;
218   i = 0;
219   for (c = *s; c != '\0'; c = *++s)
220     {
221       if (s == end)
222         break;
223       if (isdigit (c))
224         c -= '0';
225       else if (isalpha (c))
226         c = toupper (c) - 'A' + 10;
227       else
228         break;
229       if (c >= base)
230         break;
231       /* Check for overflow.  */
232       if (i > cutoff || (i == cutoff && c > cutlim))
233         overflow = 1;
234       else
235         {
236           i *= (unsigned LONG int) base;
237           i += c;
238         }
239     }
240
241   /* Check if anything actually happened.  */
242   if (s == save)
243     goto noconv;
244
245   /* Store in ENDPTR the address of one character
246      past the last character we converted.  */
247   if (endptr != NULL)
248     *endptr = (char *) s;
249
250 #if !UNSIGNED
251   /* Check for a value that is within the range of
252      `unsigned LONG int', but outside the range of `LONG int'.  */
253   if (i > (negative ?
254            -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX))
255     overflow = 1;
256 #endif
257
258   if (overflow)
259     {
260       errno = ERANGE;
261 #if UNSIGNED
262       return ULONG_MAX;
263 #else
264       return negative ? LONG_MIN : LONG_MAX;
265 #endif
266     }
267
268   /* Return the result of the appropriate sign.  */
269   return (negative ? -i : i);
270
271 noconv:
272   /* There was no number to convert.  */
273   if (endptr != NULL)
274     *endptr = (char *) nptr;
275   return 0L;
276 }
277 \f
278 /* External user entry point.  */
279
280 #ifdef weak_symbol
281 weak_symbol (strtol)
282 #endif
283
284 INT
285 strtol (nptr, endptr, base)
286      const char *nptr;
287      char **endptr;
288      int base;
289 {
290   return INTERNAL (strtol) (nptr, endptr, base, 0);
291 }