home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / textutils-1.19-src.tgz / tar.out / fsf / textutils / lib / strtol.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  363 lines

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