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