1 /*
2 * This file has been modified for the cdrkit suite.
3 *
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
6 *
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
10 *
11 */
12
13 /* @(#)astoll.c 1.3 03/06/15 Copyright 1985, 2000-2005 J. Schilling */
14 /*
15 * astoll() converts a string to long long
16 *
17 * Leading tabs and spaces are ignored.
18 * Both return pointer to the first char that has not been used.
19 * Caller must check if this means a bad conversion.
20 *
21 * leading "+" is ignored
22 * leading "0" makes conversion octal (base 8)
23 * leading "0x" makes conversion hex (base 16)
24 *
25 * Llong is silently reverted to long if the compiler does not
26 * support long long.
27 *
28 * Copyright (c) 1985, 2000-2005 J. Schilling
29 */
30 /*
31 * This program is free software; you can redistribute it and/or modify
32 * it under the terms of the GNU General Public License version 2
33 * as published by the Free Software Foundation.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License along with
41 * this program; see the file COPYING. If not, write to the Free Software
42 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 */
44
45 #include <mconfig.h>
46 #include <standard.h>
47 #include <utypes.h>
48 #include <schily.h>
49 #include <errno.h>
50 #ifndef HAVE_ERRNO_DEF
51 extern int errno;
52 #endif
53
54 #define is_space(c) ((c) == ' ' || (c) == '\t')
55 #define is_digit(c) ((c) >= '0' && (c) <= '9')
56 #define is_hex(c) (\
57 ((c) >= 'a' && (c) <= 'f') || \
58 ((c) >= 'A' && (c) <= 'F'))
59
60 #define is_lower(c) ((c) >= 'a' && (c) <= 'z')
61 #define is_upper(c) ((c) >= 'A' && (c) <= 'Z')
62 #define to_lower(c) (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A'+'a' : (c))
63
64 #if ('i' + 1) < 'j'
65 #define BASE_MAX ('i' - 'a' + 10 + 1) /* This is EBCDIC */
66 #else
67 #define BASE_MAX ('z' - 'a' + 10 + 1) /* This is ASCII */
68 #endif
69
70
71
72 EXPORT char *astoull __PR((const char *s, Ullong *l));
73 EXPORT char *astoullb __PR((const char *s, Ullong *l, int base));
74
75 EXPORT char *
astoull(s,l)76 astoull(s, l)
77 register const char *s;
78 Ullong *l;
79 {
80 return (astoullb(s, l, 0));
81 }
82
83 EXPORT char *
astoullb(s,l,base)84 astoullb(s, l, base)
85 register const char *s;
86 Ullong *l;
87 register int base;
88 {
89 #ifdef DO_SIGNED
90 int neg = 0;
91 #endif
92 register Ullong ret = (Ullong)0;
93 Ullong maxmult;
94 register int digit;
95 register char c;
96
97 if (base > BASE_MAX || base == 1 || base < 0) {
98 errno = EINVAL;
99 return ((char *)s);
100 }
101
102 while (is_space(*s))
103 s++;
104
105 if (*s == '+') {
106 s++;
107 } else if (*s == '-') {
108 #ifndef DO_SIGNED
109 errno = EINVAL;
110 return ((char *)s);
111 #else
112 s++;
113 neg++;
114 #endif
115 }
116
117 if (base == 0) {
118 if (*s == '0') {
119 base = 8;
120 s++;
121 if (*s == 'x' || *s == 'X') {
122 s++;
123 base = 16;
124 }
125 } else {
126 base = 10;
127 }
128 }
129 maxmult = TYPE_MAXVAL(Ullong) / base;
130 for (; (c = *s) != 0; s++) {
131
132 if (is_digit(c)) {
133 digit = c - '0';
134 #ifdef OLD
135 } else if (is_hex(c)) {
136 digit = to_lower(c) - 'a' + 10;
137 #else
138 } else if (is_lower(c)) {
139 digit = c - 'a' + 10;
140 } else if (is_upper(c)) {
141 digit = c - 'A' + 10;
142 #endif
143 } else {
144 break;
145 }
146
147 if (digit < base) {
148 if (ret > maxmult)
149 goto overflow;
150 ret *= base;
151 if (TYPE_MAXVAL(Ullong) - ret < digit)
152 goto overflow;
153 ret += digit;
154 } else {
155 break;
156 }
157 }
158 #ifdef DO_SIGNED
159 if (neg)
160 ret = -ret;
161 #endif
162 *l = ret;
163 return ((char *)s);
164 overflow:
165 for (; (c = *s) != 0; s++) {
166
167 if (is_digit(c)) {
168 digit = c - '0';
169 } else if (is_lower(c)) {
170 digit = c - 'a' + 10;
171 } else if (is_upper(c)) {
172 digit = c - 'A' + 10;
173 } else {
174 break;
175 }
176 if (digit >= base)
177 break;
178 }
179 *l = TYPE_MAXVAL(Ullong);
180 errno = ERANGE;
181 return ((char *)s);
182 }
183