1*c2c66affSColin Finck /* @(#)astoll.c	1.5 15/12/10 Copyright 1985, 2000-2015 J. Schilling */
2*c2c66affSColin Finck /*
3*c2c66affSColin Finck  *	astoll() converts a string to long long
4*c2c66affSColin Finck  *
5*c2c66affSColin Finck  *	Leading tabs and spaces are ignored.
6*c2c66affSColin Finck  *	Both return pointer to the first char that has not been used.
7*c2c66affSColin Finck  *	Caller must check if this means a bad conversion.
8*c2c66affSColin Finck  *
9*c2c66affSColin Finck  *	leading "+" is ignored
10*c2c66affSColin Finck  *	leading "0"  makes conversion octal (base 8)
11*c2c66affSColin Finck  *	leading "0x" makes conversion hex   (base 16)
12*c2c66affSColin Finck  *
13*c2c66affSColin Finck  *	Llong is silently reverted to long if the compiler does not
14*c2c66affSColin Finck  *	support long long.
15*c2c66affSColin Finck  *
16*c2c66affSColin Finck  *	Copyright (c) 1985, 2000-2015 J. Schilling
17*c2c66affSColin Finck  */
18*c2c66affSColin Finck /*
19*c2c66affSColin Finck  * The contents of this file are subject to the terms of the
20*c2c66affSColin Finck  * Common Development and Distribution License, Version 1.0 only
21*c2c66affSColin Finck  * (the "License").  You may not use this file except in compliance
22*c2c66affSColin Finck  * with the License.
23*c2c66affSColin Finck  *
24*c2c66affSColin Finck  * See the file CDDL.Schily.txt in this distribution for details.
25*c2c66affSColin Finck  * A copy of the CDDL is also available via the Internet at
26*c2c66affSColin Finck  * http://www.opensource.org/licenses/cddl1.txt
27*c2c66affSColin Finck  *
28*c2c66affSColin Finck  * When distributing Covered Code, include this CDDL HEADER in each
29*c2c66affSColin Finck  * file and include the License file CDDL.Schily.txt from this distribution.
30*c2c66affSColin Finck  */
31*c2c66affSColin Finck 
32*c2c66affSColin Finck #include <schily/mconfig.h>
33*c2c66affSColin Finck #include <schily/standard.h>
34*c2c66affSColin Finck #include <schily/utypes.h>
35*c2c66affSColin Finck #include <schily/schily.h>
36*c2c66affSColin Finck #include <schily/errno.h>
37*c2c66affSColin Finck 
38*c2c66affSColin Finck #define	is_space(c)	 ((c) == ' ' || (c) == '\t')
39*c2c66affSColin Finck #define	is_digit(c)	 ((c) >= '0' && (c) <= '9')
40*c2c66affSColin Finck #define	is_hex(c)	(\
41*c2c66affSColin Finck 			((c) >= 'a' && (c) <= 'f') || \
42*c2c66affSColin Finck 			((c) >= 'A' && (c) <= 'F'))
43*c2c66affSColin Finck 
44*c2c66affSColin Finck #define	is_lower(c)	((c) >= 'a' && (c) <= 'z')
45*c2c66affSColin Finck #define	is_upper(c)	((c) >= 'A' && (c) <= 'Z')
46*c2c66affSColin Finck #define	to_lower(c)	(((c) >= 'A' && (c) <= 'Z') ? (c) - 'A'+'a' : (c))
47*c2c66affSColin Finck 
48*c2c66affSColin Finck #if	('i' + 1) < 'j'
49*c2c66affSColin Finck #define	BASE_MAX	('i' - 'a' + 10 + 1)	/* This is EBCDIC */
50*c2c66affSColin Finck #else
51*c2c66affSColin Finck #define	BASE_MAX	('z' - 'a' + 10 + 1)	/* This is ASCII */
52*c2c66affSColin Finck #endif
53*c2c66affSColin Finck 
54*c2c66affSColin Finck 
55*c2c66affSColin Finck char *
astoll(s,l)56*c2c66affSColin Finck astoll(s, l)
57*c2c66affSColin Finck 	register const char *s;
58*c2c66affSColin Finck 	Llong *l;
59*c2c66affSColin Finck {
60*c2c66affSColin Finck 	return (astollb(s, l, 0));
61*c2c66affSColin Finck }
62*c2c66affSColin Finck 
63*c2c66affSColin Finck char *
astollb(s,l,base)64*c2c66affSColin Finck astollb(s, l, base)
65*c2c66affSColin Finck 	register const char *s;
66*c2c66affSColin Finck 	Llong *l;
67*c2c66affSColin Finck 	register int base;
68*c2c66affSColin Finck {
69*c2c66affSColin Finck 	int neg = 0;
70*c2c66affSColin Finck 	register ULlong ret = (ULlong)0;
71*c2c66affSColin Finck 		ULlong maxmult;
72*c2c66affSColin Finck 		ULlong maxval;
73*c2c66affSColin Finck 	register int digit;
74*c2c66affSColin Finck 	register char c;
75*c2c66affSColin Finck 
76*c2c66affSColin Finck 	if (base > BASE_MAX || base == 1 || base < 0) {
77*c2c66affSColin Finck 		seterrno(EINVAL);
78*c2c66affSColin Finck 		return ((char *)s);
79*c2c66affSColin Finck 	}
80*c2c66affSColin Finck 
81*c2c66affSColin Finck 	while (is_space(*s))
82*c2c66affSColin Finck 		s++;
83*c2c66affSColin Finck 
84*c2c66affSColin Finck 	if (*s == '+') {
85*c2c66affSColin Finck 		s++;
86*c2c66affSColin Finck 	} else if (*s == '-') {
87*c2c66affSColin Finck 		s++;
88*c2c66affSColin Finck 		neg++;
89*c2c66affSColin Finck 	}
90*c2c66affSColin Finck 
91*c2c66affSColin Finck 	if (base == 0) {
92*c2c66affSColin Finck 		if (*s == '0') {
93*c2c66affSColin Finck 			base = 8;
94*c2c66affSColin Finck 			s++;
95*c2c66affSColin Finck 			if (*s == 'x' || *s == 'X') {
96*c2c66affSColin Finck 				s++;
97*c2c66affSColin Finck 				base = 16;
98*c2c66affSColin Finck 			}
99*c2c66affSColin Finck 		} else {
100*c2c66affSColin Finck 			base = 10;
101*c2c66affSColin Finck 		}
102*c2c66affSColin Finck 	}
103*c2c66affSColin Finck 	if (neg) {
104*c2c66affSColin Finck 		/*
105*c2c66affSColin Finck 		 * Portable way to compute the positive value of "min-Llong"
106*c2c66affSColin Finck 		 * as -TYPE_MINVAL(Llong) does not work.
107*c2c66affSColin Finck 		 */
108*c2c66affSColin Finck 		maxval = ((ULlong)(-1 * (TYPE_MINVAL(Llong)+1))) + 1;
109*c2c66affSColin Finck 	} else {
110*c2c66affSColin Finck 		maxval = TYPE_MAXVAL(Llong);
111*c2c66affSColin Finck 	}
112*c2c66affSColin Finck 	maxmult = maxval / base;
113*c2c66affSColin Finck 	for (; (c = *s) != 0; s++) {
114*c2c66affSColin Finck 
115*c2c66affSColin Finck 		if (is_digit(c)) {
116*c2c66affSColin Finck 			digit = c - '0';
117*c2c66affSColin Finck 		} else if (is_lower(c)) {
118*c2c66affSColin Finck 			digit = c - 'a' + 10;
119*c2c66affSColin Finck 		} else if (is_upper(c)) {
120*c2c66affSColin Finck 			digit = c - 'A' + 10;
121*c2c66affSColin Finck 		} else {
122*c2c66affSColin Finck 			break;
123*c2c66affSColin Finck 		}
124*c2c66affSColin Finck 
125*c2c66affSColin Finck 		if (digit < base) {
126*c2c66affSColin Finck 			if (ret > maxmult)
127*c2c66affSColin Finck 				goto overflow;
128*c2c66affSColin Finck 			ret *= base;
129*c2c66affSColin Finck 			if (maxval - ret < digit)
130*c2c66affSColin Finck 				goto overflow;
131*c2c66affSColin Finck 			ret += digit;
132*c2c66affSColin Finck 		} else {
133*c2c66affSColin Finck 			break;
134*c2c66affSColin Finck 		}
135*c2c66affSColin Finck 	}
136*c2c66affSColin Finck 	if (neg) {
137*c2c66affSColin Finck 		*l = (Llong)-1 * ret;
138*c2c66affSColin Finck 	} else {
139*c2c66affSColin Finck 		*l = (Llong)ret;
140*c2c66affSColin Finck 	}
141*c2c66affSColin Finck 	return ((char *)s);
142*c2c66affSColin Finck overflow:
143*c2c66affSColin Finck 	for (; (c = *s) != 0; s++) {
144*c2c66affSColin Finck 
145*c2c66affSColin Finck 		if (is_digit(c)) {
146*c2c66affSColin Finck 			digit = c - '0';
147*c2c66affSColin Finck 		} else if (is_lower(c)) {
148*c2c66affSColin Finck 			digit = c - 'a' + 10;
149*c2c66affSColin Finck 		} else if (is_upper(c)) {
150*c2c66affSColin Finck 			digit = c - 'A' + 10;
151*c2c66affSColin Finck 		} else {
152*c2c66affSColin Finck 			break;
153*c2c66affSColin Finck 		}
154*c2c66affSColin Finck 		if (digit >= base)
155*c2c66affSColin Finck 			break;
156*c2c66affSColin Finck 	}
157*c2c66affSColin Finck 	if (neg) {
158*c2c66affSColin Finck 		*l = TYPE_MINVAL(Llong);
159*c2c66affSColin Finck 	} else {
160*c2c66affSColin Finck 		*l = TYPE_MAXVAL(Llong);
161*c2c66affSColin Finck 	}
162*c2c66affSColin Finck 	seterrno(ERANGE);
163*c2c66affSColin Finck 	return ((char *)s);
164*c2c66affSColin Finck }
165