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