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