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