source: trunk/third/enscript/compat/strtol.c @ 17620

Revision 17620, 8.4 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17619, which included commits to RCS files with non-trunk default branches.
Line 
1/* strtol - Convert string representation of a number into an integer value.
2   Copyright (C) 1991, 92, 94, 95, 96, 97 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Library General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Library General Public License for more details.
14
15   You should have received a copy of the GNU Library General Public
16   License along with the GNU C Library; see the file COPYING.LIB.  If not,
17   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.  */
19
20#if 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
33extern int errno;
34#endif
35#ifndef __set_errno
36# define __set_errno(Val) errno = (Val)
37#endif
38
39#ifdef HAVE_LIMITS_H
40# include <limits.h>
41#endif
42
43#ifdef STDC_HEADERS
44# include <stddef.h>
45# include <stdlib.h>
46# include <string.h>
47#else
48# ifndef NULL
49#  define NULL 0
50# endif
51#endif
52
53#ifdef USE_NUMBER_GROUPING
54# include "../locale/localeinfo.h"
55#endif
56
57/* Nonzero if we are defining `strtoul' or `strtouq', operating on
58   unsigned integers.  */
59#ifndef UNSIGNED
60# define UNSIGNED 0
61# define INT LONG int
62#else
63# define INT unsigned LONG int
64#endif
65
66/* Determine the name.  */
67#if UNSIGNED
68# ifdef USE_WIDE_CHAR
69#  ifdef QUAD
70#   define strtol wcstouq
71#  else
72#   define strtol wcstoul
73#  endif
74# else
75#  ifdef QUAD
76#   define strtol strtouq
77#  else
78#   define strtol strtoul
79#  endif
80# endif
81#else
82# ifdef USE_WIDE_CHAR
83#  ifdef QUAD
84#   define strtol wcstoq
85#  else
86#   define strtol wcstol
87#  endif
88# else
89#  ifdef QUAD
90#   define strtol strtoq
91#  endif
92# endif
93#endif
94
95/* If QUAD is defined, we are defining `strtoq' or `strtouq',
96   operating on `long long int's.  */
97#ifdef QUAD
98# define LONG long long
99# undef LONG_MIN
100# define LONG_MIN LONG_LONG_MIN
101# undef LONG_MAX
102# define LONG_MAX LONG_LONG_MAX
103# undef ULONG_MAX
104# define ULONG_MAX ULONG_LONG_MAX
105# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
106   /* Work around gcc bug with using this constant.  */
107   static const unsigned long long int maxquad = ULONG_LONG_MAX;
108#  undef ULONG_MAX
109#  define ULONG_MAX maxquad
110# endif
111#else
112# define LONG long
113
114#ifndef ULONG_MAX
115# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
116#endif
117#ifndef LONG_MAX
118# define LONG_MAX ((long int) (ULONG_MAX >> 1))
119#endif
120#endif
121
122#ifdef USE_WIDE_CHAR
123# include <wchar.h>
124# include <wctype.h>
125# define L_(Ch) L##Ch
126# define UCHAR_TYPE wint_t
127# define STRING_TYPE wchar_t
128# define ISSPACE(Ch) iswspace (Ch)
129# define ISALPHA(Ch) iswalpha (Ch)
130# define TOUPPER(Ch) towupper (Ch)
131#else
132# define L_(Ch) Ch
133# define UCHAR_TYPE unsigned char
134# define STRING_TYPE char
135# define ISSPACE(Ch) isspace (Ch)
136# define ISALPHA(Ch) isalpha (Ch)
137# define TOUPPER(Ch) toupper (Ch)
138#endif
139
140#ifdef __STDC__
141# define INTERNAL(X) INTERNAL1(X)
142# define INTERNAL1(X) __##X##_internal
143# define WEAKNAME(X) WEAKNAME1(X)
144#else
145# define INTERNAL(X) __/**/X/**/_internal
146#endif
147
148#ifdef USE_NUMBER_GROUPING
149/* This file defines a function to check for correct grouping.  */
150# include "grouping.h"
151#endif
152
153
154/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
155   If BASE is 0 the base is determined by the presence of a leading
156   zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
157   If BASE is < 2 or > 36, it is reset to 10.
158   If ENDPTR is not NULL, a pointer to the character after the last
159   one converted is stored in *ENDPTR.  */
160
161INT
162INTERNAL (strtol) (nptr, endptr, base, group)
163     const STRING_TYPE *nptr;
164     STRING_TYPE **endptr;
165     int base;
166     int group;
167{
168  int negative;
169  register unsigned LONG int cutoff;
170  register unsigned int cutlim;
171  register unsigned LONG int i;
172  register const STRING_TYPE *s;
173  register UCHAR_TYPE c;
174  const STRING_TYPE *save, *end;
175  int overflow;
176
177#ifdef USE_NUMBER_GROUPING
178  /* The thousands character of the current locale.  */
179  wchar_t thousands;
180  /* The numeric grouping specification of the current locale,
181     in the format described in <locale.h>.  */
182  const char *grouping;
183
184  if (group)
185    {
186      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
187      if (*grouping <= 0 || *grouping == CHAR_MAX)
188        grouping = NULL;
189      else
190        {
191          /* Figure out the thousands separator character.  */
192          if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
193                      strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
194            thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
195          if (thousands == L'\0')
196            grouping = NULL;
197        }
198    }
199  else
200    grouping = NULL;
201#endif
202
203  if (base < 0 || base == 1 || base > 36)
204    {
205      __set_errno (EINVAL);
206      return 0;
207    }
208
209  save = s = nptr;
210
211  /* Skip white space.  */
212  while (ISSPACE (*s))
213    ++s;
214  if (*s == L_('\0'))
215    goto noconv;
216
217  /* Check for a sign.  */
218  if (*s == L_('-'))
219    {
220      negative = 1;
221      ++s;
222    }
223  else if (*s == L_('+'))
224    {
225      negative = 0;
226      ++s;
227    }
228  else
229    negative = 0;
230
231  if (base == 16 && s[0] == L_('0') && TOUPPER (s[1]) == L_('X'))
232    s += 2;
233
234  /* If BASE is zero, figure it out ourselves.  */
235  if (base == 0)
236    if (*s == L_('0'))
237      {
238        if (TOUPPER (s[1]) == L_('X'))
239          {
240            s += 2;
241            base = 16;
242          }
243        else
244          base = 8;
245      }
246    else
247      base = 10;
248
249  /* Save the pointer so we can check later if anything happened.  */
250  save = s;
251
252#ifdef USE_NUMBER_GROUPING
253  if (group)
254    {
255      /* Find the end of the digit string and check its grouping.  */
256      end = s;
257      for (c = *end; c != L_('\0'); c = *++end)
258        if ((wchar_t) c != thousands
259            && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
260            && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
261          break;
262      if (*s == thousands)
263        end = s;
264      else
265        end = correctly_grouped_prefix (s, end, thousands, grouping);
266    }
267  else
268#endif
269    end = NULL;
270
271  cutoff = ULONG_MAX / (unsigned LONG int) base;
272  cutlim = ULONG_MAX % (unsigned LONG int) base;
273
274  overflow = 0;
275  i = 0;
276  for (c = *s; c != L_('\0'); c = *++s)
277    {
278      if (s == end)
279        break;
280      if (c >= L_('0') && c <= L_('9'))
281        c -= L_('0');
282      else if (ISALPHA (c))
283        c = TOUPPER (c) - L_('A') + 10;
284      else
285        break;
286      if ((int) c >= base)
287        break;
288      /* Check for overflow.  */
289      if (i > cutoff || (i == cutoff && c > cutlim))
290        overflow = 1;
291      else
292        {
293          i *= (unsigned LONG int) base;
294          i += c;
295        }
296    }
297
298  /* Check if anything actually happened.  */
299  if (s == save)
300    goto noconv;
301
302  /* Store in ENDPTR the address of one character
303     past the last character we converted.  */
304  if (endptr != NULL)
305    *endptr = (STRING_TYPE *) s;
306
307#if !UNSIGNED
308  /* Check for a value that is within the range of
309     `unsigned LONG int', but outside the range of `LONG int'.  */
310  if (overflow == 0
311      && i > (negative
312              ? -((unsigned LONG int) (LONG_MIN + 1)) + 1
313              : (unsigned LONG int) LONG_MAX))
314    overflow = 1;
315#endif
316
317  if (overflow)
318    {
319      __set_errno (ERANGE);
320#if UNSIGNED
321      return ULONG_MAX;
322#else
323      return negative ? LONG_MIN : LONG_MAX;
324#endif
325    }
326
327  /* Return the result of the appropriate sign.  */
328  return (negative ? -i : i);
329
330noconv:
331  /* We must handle a special case here: the base is 0 or 16 and the
332     first two characters are '0' and 'x', but the rest are no
333     hexadecimal digits.  This is no error case.  We return 0 and
334     ENDPTR points to the `x`.  */
335  if (endptr != NULL)
336    if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
337        && save[-2] == L_('0'))
338      *endptr = (STRING_TYPE *) &save[-1];
339    else
340      /*  There was no number to convert.  */
341      *endptr = (STRING_TYPE *) nptr;
342
343  return 0L;
344}
345
346/* External user entry point.  */
347
348#if _LIBC - 0 == 0
349# undef PARAMS
350# if defined (__STDC__) && __STDC__
351#  define PARAMS(Args) Args
352# else
353#  define PARAMS(Args) ()
354# endif
355
356/* Prototype.  */
357INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
358#endif
359
360
361INT
362#ifdef weak_function
363weak_function
364#endif
365strtol (nptr, endptr, base)
366     const STRING_TYPE *nptr;
367     STRING_TYPE **endptr;
368     int base;
369{
370  return INTERNAL (strtol) (nptr, endptr, base, 0);
371}
Note: See TracBrowser for help on using the repository browser.