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