xref: /inferno-os/libkern/strtoul.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include <lib9.h>
2 
3 #define ULONG_MAX	4294967295UL
4 
5 ulong
strtoul(char * nptr,char ** endptr,int base)6 strtoul(char *nptr, char **endptr, int base)
7 {
8 	char *p;
9 	ulong n, nn, m;
10 	int c, ovfl, neg, v, ndig;
11 
12 	p = (char*)nptr;
13 	neg = 0;
14 	n = 0;
15 	ndig = 0;
16 	ovfl = 0;
17 
18 	/*
19 	 * White space
20 	 */
21 	for(;;p++){
22 		switch(*p){
23 		case ' ':
24 		case '\t':
25 		case '\n':
26 		case '\f':
27 		case '\r':
28 		case '\v':
29 			continue;
30 		}
31 		break;
32 	}
33 
34 	/*
35 	 * Sign
36 	 */
37 	if(*p=='-' || *p=='+')
38 		if(*p++ == '-')
39 			neg = 1;
40 
41 	/*
42 	 * Base
43 	 */
44 	if(base==0){
45 		if(*p != '0')
46 			base = 10;
47 		else{
48 			base = 8;
49 			if(p[1]=='x' || p[1]=='X')
50 				base = 16;
51 		}
52 	}
53  	if(base<2 || 36<base)
54 		goto Return;
55 	if(base==16 && *p=='0'){
56 		if(p[1]=='x' || p[1]=='X')
57 			if(('0' <= p[2] && p[2] <= '9')
58 			 ||('a' <= p[2] && p[2] <= 'f')
59 			 ||('A' <= p[2] && p[2] <= 'F'))
60 				p += 2;
61 	}
62 	/*
63 	 * Non-empty sequence of digits
64 	 */
65 	n = 0;
66 	m = ULONG_MAX/base;
67 	for(;; p++,ndig++){
68 		c = *p;
69 		v = base;
70 		if('0'<=c && c<='9')
71 			v = c - '0';
72 		else if('a'<=c && c<='z')
73 			v = c - 'a' + 10;
74 		else if('A'<=c && c<='Z')
75 			v = c - 'A' + 10;
76 		if(v >= base)
77 			break;
78 		if(n > m)
79 			ovfl = 1;
80 		nn = n*base + v;
81 		if(nn < n)
82 			ovfl = 1;
83 		n = nn;
84 	}
85 
86     Return:
87 	if(ndig == 0)
88 		p = nptr;
89 	if(endptr)
90 		*endptr = p;
91 	if(ovfl)
92 		return ULONG_MAX;
93 	if(neg)
94 		return -n;
95 	return n;
96 }
97