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