Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / librols / astoull.c
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 *
76 astoull(s, l)
77         register const char *s;
78         Ullong *l;
79 {
80         return (astoullb(s, l, 0));
81 }
82
83 EXPORT char *
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 }