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