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