]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/lib/strtoul.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / lib / strtoul.c
1 /*
2  * strtol : convert a string to long.
3  *
4  * Andy Wilson, 2-Oct-89.
5  */
6
7 #include <errno.h>
8 #include <ctype.h>
9 #include <stdio.h>
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #ifndef ULONG_MAX
16 #define ULONG_MAX       ((unsigned long)(~0L))          /* 0xFFFFFFFF */
17 #endif
18
19 extern int errno;
20
21 unsigned long
22 strtoul(s, ptr, base)
23      const char *s; char **ptr; int base;
24 {
25   unsigned long total = 0;
26   unsigned digit;
27   const char *start=s;
28   int did_conversion=0;
29   int overflow = 0;
30   int negate = 0;
31   unsigned long maxdiv, maxrem;
32
33   if (s==NULL)
34     {
35       errno = ERANGE;
36       if (!ptr)
37         *ptr = (char *)start;
38       return 0L;
39     }
40
41   while (isspace(*s))
42     s++;
43   if (*s == '+')
44     s++;
45   else if (*s == '-')
46     s++, negate = 1;
47   if (base==0 || base==16) /*  the 'base==16' is for handling 0x */
48     {
49       int tmp;
50
51       /*
52        * try to infer base from the string
53        */
54       if (*s != '0')
55         tmp = 10;       /* doesn't start with 0 - assume decimal */
56       else if (s[1] == 'X' || s[1] == 'x')
57         tmp = 16, s += 2; /* starts with 0x or 0X - hence hex */
58       else
59         tmp = 8;        /* starts with 0 - hence octal */
60       if (base==0)
61         base = (int)tmp;
62     }
63
64   maxdiv = ULONG_MAX / base;
65   maxrem = ULONG_MAX % base;
66
67   while ((digit = *s) != '\0')
68     {
69       if (digit >= '0' && digit < ('0'+base))
70         digit -= '0';
71       else
72         if (base > 10)
73           {
74             if (digit >= 'a' && digit < ('a'+(base-10)))
75               digit = digit - 'a' + 10;
76             else if (digit >= 'A' && digit < ('A'+(base-10)))
77               digit = digit - 'A' + 10;
78             else
79               break;
80           }
81         else
82           break;
83       did_conversion = 1;
84       if (total > maxdiv
85           || (total == maxdiv && digit > maxrem))
86         overflow = 1;
87       total = (total * base) + digit;
88       s++;
89     }
90   if (overflow)
91     {
92       errno = ERANGE;
93       if (ptr != NULL)
94         *ptr = (char *)s;
95       return (ULONG_MAX);
96     }
97   if (ptr != NULL)
98     *ptr = (char *) ((did_conversion) ? (char *)s : (char *)start);
99   return negate ? -total : total;
100 }