xref: /inferno-os/libkern/strtol.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include <lib9.h>
2 
3 #define LONG_MAX	2147483647L
4 #define LONG_MIN	-2147483648L
5 
6 long
strtol(char * nptr,char ** endptr,int base)7 strtol(char *nptr, char **endptr, int base)
8 {
9 	char *p;
10 	long n, nn;
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 		if(*p != '0')
47 			base = 10;
48 		else{
49 			base = 8;
50 			if(p[1]=='x' || p[1]=='X'){
51 				p += 2;
52 				base = 16;
53 			}
54 		}
55 	}else if(base==16 && *p=='0'){
56 		if(p[1]=='x' || p[1]=='X')
57 			p += 2;
58 	}else if(base<0 || 36<base)
59 		goto Return;
60 
61 	/*
62 	 * Non-empty sequence of digits
63 	 */
64 	for(;; p++,ndig++){
65 		c = *p;
66 		v = base;
67 		if('0'<=c && c<='9')
68 			v = c - '0';
69 		else if('a'<=c && c<='z')
70 			v = c - 'a' + 10;
71 		else if('A'<=c && c<='Z')
72 			v = c - 'A' + 10;
73 		if(v >= base)
74 			break;
75 		nn = n*base + v;
76 		if(nn < n)
77 			ovfl = 1;
78 		n = nn;
79 	}
80 
81     Return:
82 	if(ndig == 0)
83 		p = nptr;
84 	if(endptr)
85 		*endptr = p;
86 	if(ovfl){
87 		if(neg)
88 			return LONG_MIN;
89 		return LONG_MAX;
90 	}
91 	if(neg)
92 		return -n;
93 	return n;
94 }
95