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