aboutsummaryrefslogtreecommitdiff
path: root/src/base/string/raw/asint.c
blob: 6751146cf31399d846340fd5b5081be0aead2545 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <u.h>
#include <base.h>

long
strยทasint(char *s, char **end, int base)
{
    char *p;
	vlong n, nn, m;
	int c, ovfl, v, neg, ndig;

	p    = s;
	neg  = 0;
	n    = 0;
	ndig = 0;
	ovfl = 0;

	/* White space */
	for(;; p++){
		switch(*p){
		case ' ':
		case '\t':
		case '\n':
		case '\f':
		case '\r':
		case '\v':
			continue;
		}
		break;
	}

	/* Sign */
	if(*p=='-' || *p=='+')
		if(*p++ == '-')
			neg = 1;

	/* Base */
	if(base==0){
		base=10;
		if(*p == '0'){
			base = 8;
			if(p[1]=='x'||p[1]=='X'){
				p += 2;
				base = 16;
			}
		}
	}else if(base==16 && *p=='0'){
		if(p[1]=='x' || p[1]=='X')
			p += 2;
	}else if(base<0 || 36<base)
		goto Return;

	/* Non-empty sequence of digits */
	m = LONG_MAX/base;
	for(;; p++,ndig++){
		c = *p;
		v = base;
		if('0'<=c && c<='9')
			v = c - '0';
		else if('a'<=c && c<='z')
			v = c - 'a' + 10;
		else if('A'<=c && c<='Z')
			v = c - 'A' + 10;
		if(v >= base)
			break;
		if(n > m)
			ovfl = 1;
		nn = n*base + v;
		if(nn < n)
			ovfl = 1;
		n = nn;
	}

Return:
	if(ndig == 0)
		p = s;
	if(end)
		*end = p;
	if(ovfl){
		if(neg)
			return LONG_MIN;
		return LONG_MAX;
	}
	if(neg)
		return -n;
	return n;
}