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