xref: /plan9/sys/src/libc/port/strtoull.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 
4 #define UVLONG_MAX	(1LL<<63)
5 
6 uvlong
strtoull(char * nptr,char ** endptr,int base)7 strtoull(char *nptr, char **endptr, int base)
8 {
9 	char *p;
10 	uvlong n, nn, m;
11 	int c, ovfl, v, neg, 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 		base = 10;
47 		if(*p == '0') {
48 			base = 8;
49 			if(p[1] == 'x' || p[1] == 'X'){
50 				p += 2;
51 				base = 16;
52 			}
53 		}
54 	} else
55 	if(base == 16 && *p == '0') {
56 		if(p[1] == 'x' || p[1] == 'X')
57 			p += 2;
58 	} else
59 	if(base < 0 || 36 < base)
60 		goto Return;
61 
62 	/*
63 	 * Non-empty sequence of digits
64 	 */
65 	m = UVLONG_MAX/base;
66 	for(;; p++,ndig++) {
67 		c = *p;
68 		v = base;
69 		if('0' <= c && c <= '9')
70 			v = c - '0';
71 		else
72 		if('a' <= c && c <= 'z')
73 			v = c - 'a' + 10;
74 		else
75 		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 UVLONG_MAX;
94 	if(neg)
95 		return -n;
96 	return n;
97 }
98