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