xref: /plan9/sys/src/libc/port/strtol.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier #define LONG_MAX	2147483647L
53e12c5d1SDavid du Colombier #define LONG_MIN	-2147483648L
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier long
strtol(char * nptr,char ** endptr,int base)83e12c5d1SDavid du Colombier strtol(char *nptr, char **endptr, int base)
93e12c5d1SDavid du Colombier {
103e12c5d1SDavid du Colombier 	char *p;
11*7dd7cddfSDavid du Colombier 	long n, nn, m;
123e12c5d1SDavid du Colombier 	int c, ovfl, v, neg, ndig;
133e12c5d1SDavid du Colombier 
143e12c5d1SDavid du Colombier 	p = nptr;
153e12c5d1SDavid du Colombier 	neg = 0;
163e12c5d1SDavid du Colombier 	n = 0;
173e12c5d1SDavid du Colombier 	ndig = 0;
183e12c5d1SDavid du Colombier 	ovfl = 0;
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier 	/*
213e12c5d1SDavid du Colombier 	 * White space
223e12c5d1SDavid du Colombier 	 */
233e12c5d1SDavid du Colombier 	for(;; p++) {
243e12c5d1SDavid du Colombier 		switch(*p) {
253e12c5d1SDavid du Colombier 		case ' ':
263e12c5d1SDavid du Colombier 		case '\t':
273e12c5d1SDavid du Colombier 		case '\n':
283e12c5d1SDavid du Colombier 		case '\f':
293e12c5d1SDavid du Colombier 		case '\r':
303e12c5d1SDavid du Colombier 		case '\v':
313e12c5d1SDavid du Colombier 			continue;
323e12c5d1SDavid du Colombier 		}
333e12c5d1SDavid du Colombier 		break;
343e12c5d1SDavid du Colombier 	}
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier 	/*
373e12c5d1SDavid du Colombier 	 * Sign
383e12c5d1SDavid du Colombier 	 */
393e12c5d1SDavid du Colombier 	if(*p=='-' || *p=='+')
403e12c5d1SDavid du Colombier 		if(*p++ == '-')
413e12c5d1SDavid du Colombier 			neg = 1;
423e12c5d1SDavid du Colombier 
433e12c5d1SDavid du Colombier 	/*
443e12c5d1SDavid du Colombier 	 * Base
453e12c5d1SDavid du Colombier 	 */
463e12c5d1SDavid du Colombier 	if(base==0) {
473e12c5d1SDavid du Colombier 		base = 10;
48*7dd7cddfSDavid du Colombier 		if(*p == '0') {
493e12c5d1SDavid du Colombier 			base = 8;
503e12c5d1SDavid du Colombier 			if(p[1]=='x' || p[1]=='X') {
513e12c5d1SDavid du Colombier 				p += 2;
523e12c5d1SDavid du Colombier 				base = 16;
533e12c5d1SDavid du Colombier 			}
543e12c5d1SDavid du Colombier 		}
55*7dd7cddfSDavid du Colombier 	} else
56*7dd7cddfSDavid du Colombier 	if(base==16 && *p=='0'){
573e12c5d1SDavid du Colombier 		if(p[1]=='x' || p[1]=='X')
583e12c5d1SDavid du Colombier 			p += 2;
59*7dd7cddfSDavid du Colombier 	} else
60*7dd7cddfSDavid du Colombier 	if(base<0 || 36<base)
613e12c5d1SDavid du Colombier 		goto Return;
623e12c5d1SDavid du Colombier 
633e12c5d1SDavid du Colombier 	/*
643e12c5d1SDavid du Colombier 	 * Non-empty sequence of digits
653e12c5d1SDavid du Colombier 	 */
66*7dd7cddfSDavid du Colombier 	m = LONG_MAX/base;
673e12c5d1SDavid du Colombier 	for(;; p++,ndig++){
683e12c5d1SDavid du Colombier 		c = *p;
693e12c5d1SDavid du Colombier 		v = base;
703e12c5d1SDavid du Colombier 		if('0'<=c && c<='9')
713e12c5d1SDavid du Colombier 			v = c - '0';
72*7dd7cddfSDavid du Colombier 		else
73*7dd7cddfSDavid du Colombier 		if('a'<=c && c<='z')
743e12c5d1SDavid du Colombier 			v = c - 'a' + 10;
75*7dd7cddfSDavid du Colombier 		else
76*7dd7cddfSDavid du Colombier 		if('A'<=c && c<='Z')
773e12c5d1SDavid du Colombier 			v = c - 'A' + 10;
783e12c5d1SDavid du Colombier 		if(v >= base)
793e12c5d1SDavid du Colombier 			break;
80*7dd7cddfSDavid du Colombier 		if(n > m)
81*7dd7cddfSDavid du Colombier 			ovfl = 1;
823e12c5d1SDavid du Colombier 		nn = n*base + v;
833e12c5d1SDavid du Colombier 		if(nn < n)
843e12c5d1SDavid du Colombier 			ovfl = 1;
853e12c5d1SDavid du Colombier 		n = nn;
863e12c5d1SDavid du Colombier 	}
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier Return:
893e12c5d1SDavid du Colombier 	if(ndig == 0)
903e12c5d1SDavid du Colombier 		p = nptr;
913e12c5d1SDavid du Colombier 	if(endptr)
923e12c5d1SDavid du Colombier 		*endptr = p;
933e12c5d1SDavid du Colombier 	if(ovfl){
943e12c5d1SDavid du Colombier 		if(neg)
953e12c5d1SDavid du Colombier 			return LONG_MIN;
963e12c5d1SDavid du Colombier 		return LONG_MAX;
973e12c5d1SDavid du Colombier 	}
983e12c5d1SDavid du Colombier 	if(neg)
993e12c5d1SDavid du Colombier 		return -n;
1003e12c5d1SDavid du Colombier 	return n;
1013e12c5d1SDavid du Colombier }
102