str.cc revision 56
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <iostream>
30
31#include <string.h>
32#include <ctype.h>
33
34#include <string>
35#include <vector>
36
37#include "base/intmath.hh"
38#include "base/str.hh"
39
40using namespace std;
41
42void
43tokenize(vector<string>& v, const string &s, char token, bool ignore)
44{
45    string::size_type first = 0;
46    string::size_type last = s.find_first_of(token);
47
48    if (ignore) {
49        if (last == first) {
50            while (last == first)
51                last = s.find_first_of(token, ++first);
52
53            if (last == string::npos) {
54                v.push_back(s);
55                return;
56            }
57        }
58    }
59
60    while (last != string::npos) {
61        v.push_back(s.substr(first, last - first));
62
63        if (ignore) {
64            first = s.find_first_not_of(token, last + 1);
65
66            if (first == string::npos)
67                return;
68        } else
69            first = last + 1;
70
71        last = s.find_first_of(token, first);
72    }
73
74    v.push_back(s.substr(first));
75}
76
77template <class T>
78inline bool
79__to_number(string value, T &retval)
80{
81    static const T maxnum = ((T)-1);
82    static const bool sign = maxnum < 0;
83    static const T hexmax = maxnum & (((T)1 << (sizeof(T) * 8 - 4)) - 1);
84    static const T octmax = maxnum & (((T)1 << (sizeof(T) * 8 - 3)) - 1);
85    static const T signmax =
86        (sign) ? maxnum & (((T)1 << (sizeof(T) * 8 - 1)) - 1) : maxnum;
87    static const T decmax = signmax / 10 - 1;
88
89#if 0
90    cout << "maxnum =  0x" << hex << maxnum << "\n"
91         << "sign =    0x" << hex << sign << "\n"
92         << "hexmax =  0x" << hex << hexmax << "\n"
93         << "octmax =  0x" << hex << octmax << "\n"
94         << "signmax = 0x" << hex << signmax << "\n"
95         << "decmax =  0x" << hex << decmax << "\n";
96#endif
97
98    eat_white(value);
99
100    bool negative = false;
101    bool hex = false;
102    bool oct = false;
103    int last = value.size() - 1;
104    retval = 0;
105    int i = 0;
106
107    char c = value[i];
108    if (!IsDec(c)) {
109        if (c == '-' && sign)
110            negative = true;
111        else
112            return false;
113    }
114    else {
115        retval += c - '0';
116        if (last == 0) return true;
117    }
118
119    if (c == '0')
120        oct = true;
121
122    c = value[++i];
123    if (oct) {
124        if (sign && negative)
125            return false;
126
127        if (!IsOct(c)) {
128            if (c == 'X' || c == 'x') {
129                hex = true;
130                oct = false;
131            } else
132                return false;
133        }
134        else
135            retval += c - '0';
136    } else if (!IsDec(c))
137        goto multiply;
138    else {
139        if (sign && negative && c == '0')
140            return false;
141
142        retval *= 10;
143        retval += c - '0';
144        if (last == 1) {
145            if (sign && negative) retval = -retval;
146            return true;
147        }
148    }
149
150    if (hex) {
151        if (last == 1)
152            return false;
153
154        for (i = 2; i <= last ; i++) {
155            c = value[i];
156            if (!IsHex(c))
157                return false;
158
159            if (retval > hexmax) return false;
160            retval *= 16;
161            retval += Hex2Int(c);
162        }
163        return true;
164    } else if (oct) {
165        for (i = 2; i <= last ; i++) {
166            c = value[i];
167            if (!IsOct(c))
168                return false;
169
170            if (retval > octmax) return false;
171            retval *= 8;
172            retval += (c - '0');
173        }
174        return true;
175    }
176
177    for (i = 2; i < last ; i++) {
178        c = value[i];
179        if (!IsDec(c))
180            goto multiply;
181
182        if (retval > decmax) return false;
183        retval *= 10;
184        retval += c - '0';
185        if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
186            return false;
187    }
188
189    c = value[last];
190    if (IsDec(c)) {
191
192        if (retval > decmax) return false;
193        retval *= 10;
194        retval += c - '0';
195        if (sign && negative) {
196            if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
197                retval >= (T)-signmax)
198                return false;
199            retval = -retval;
200        }
201        else
202            if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
203                return false;
204        return true;
205    }
206
207  multiply:
208    signed long long mult = 1;
209    T val;
210    switch (c) {
211      case 'k':
212      case 'K':
213        if (i != last) return false;
214        mult = 1024;
215        val = signmax / mult;
216        break;
217      case 'm':
218      case 'M':
219        if (i != last) return false;
220        mult = 1024 * 1024;
221        val = signmax / mult;
222        break;
223      case 'g':
224      case 'G':
225        if (i != last) return false;
226        mult = 1024 * 1024 * 1024;
227        val = signmax / mult;
228        break;
229      case 'e':
230      case 'E':
231        if (i >= last) return false;
232
233        mult = 0;
234        for (i++; i <= last; i++) {
235            c = value[i];
236            if (!IsDec(c))
237                return false;
238
239            mult *= 10;
240            mult += c - '0';
241        }
242
243        for (i = 0; i < mult; i++) {
244            if (retval > signmax / 10)
245                return false;
246            retval *= 10;
247            if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
248                return false;
249        }
250        if (sign && negative) {
251            if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
252                retval >= (T)-signmax)
253                return false;
254            retval = -retval;
255        }
256        else
257            if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
258                return false;
259
260        return true;
261
262      default:
263        return false;
264    }
265
266    if (sign && negative)
267        return false;
268
269    if (mult > (unsigned long long)signmax)
270        return false;
271
272    if (retval > val)
273        return false;
274
275    retval *= mult;
276
277    return true;
278}
279
280#define STN(type) \
281template<> \
282bool to_number<type>(const string &value, type &retval) \
283{ return __to_number(value, retval); }
284
285STN(unsigned long long);
286STN(signed long long);
287STN(unsigned long);
288STN(signed long);
289STN(unsigned int);
290STN(signed int);
291STN(unsigned short);
292STN(signed short);
293STN(unsigned char);
294STN(signed char);
295
296template<>
297bool to_number<bool>(const string &value, bool &retval)
298{
299    string lowered = to_lower(value);
300
301    if (value == "0") {
302        retval = false;
303        return true;
304    }
305
306    if (value == "1"){
307        retval = true;
308        return true;
309    }
310
311    if (lowered == "false") {
312        retval = false;
313        return true;
314    }
315
316    if (lowered == "true"){
317        retval = true;
318        return true;
319    }
320
321    if (lowered == "no") {
322        retval = false;
323        return true;
324    }
325
326    if (lowered == "yes"){
327        retval = true;
328        return true;
329    }
330
331    return false;
332}
333