str.cc revision 239
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
77/**
78 * @todo This function will not handle the smallest negative decimal
79 * value for a signed type
80 */
81
82template <class T>
83inline bool
84__to_number(string value, T &retval)
85{
86    static const T maxnum = ((T)-1);
87    static const bool sign = maxnum < 0;
88    static const int bits = sizeof(T) * 8;
89    static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1);
90    static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1);
91    static const T signmax =
92        (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum;
93    static const T decmax = signmax / 10;
94
95#if 0
96    cout << "maxnum =  0x" << hex << (unsigned long long)maxnum << "\n"
97         << "sign =    0x" << hex << (unsigned long long)sign << "\n"
98         << "hexmax =  0x" << hex << (unsigned long long)hexmax << "\n"
99         << "octmax =  0x" << hex << (unsigned long long)octmax << "\n"
100         << "signmax = 0x" << hex << (unsigned long long)signmax << "\n"
101         << "decmax =  0x" << hex << (unsigned long long)decmax << "\n";
102#endif
103
104    eat_white(value);
105
106    bool negative = false;
107    bool hex = false;
108    bool oct = false;
109    int last = value.size() - 1;
110    retval = 0;
111    int i = 0;
112
113    char c = value[i];
114    if (!IsDec(c)) {
115        if (c == '-' && sign)
116            negative = true;
117        else
118            return false;
119    }
120    else {
121        retval += c - '0';
122        if (last == 0) return true;
123    }
124
125    if (c == '0')
126        oct = true;
127
128    c = value[++i];
129    if (oct) {
130        if (sign && negative)
131            return false;
132
133        if (!IsOct(c)) {
134            if (c == 'X' || c == 'x') {
135                hex = true;
136                oct = false;
137            } else
138                return false;
139        }
140        else
141            retval += c - '0';
142    } else if (!IsDec(c))
143        goto multiply;
144    else {
145        if (sign && negative && c == '0')
146            return false;
147
148        retval *= 10;
149        retval += c - '0';
150        if (last == 1) {
151            if (sign && negative) retval = -retval;
152            return true;
153        }
154    }
155
156    if (hex) {
157        if (last == 1)
158            return false;
159
160        for (i = 2; i <= last ; i++) {
161            c = value[i];
162            if (!IsHex(c))
163                return false;
164
165            if (retval > hexmax) return false;
166            retval *= 16;
167            retval += Hex2Int(c);
168        }
169        return true;
170    } else if (oct) {
171        for (i = 2; i <= last ; i++) {
172            c = value[i];
173            if (!IsOct(c))
174                return false;
175
176            if (retval > octmax) return false;
177            retval *= 8;
178            retval += (c - '0');
179        }
180        return true;
181    }
182
183    for (i = 2; i < last ; i++) {
184        c = value[i];
185        if (!IsDec(c))
186            goto multiply;
187
188        if (retval > decmax) return false;
189        bool atmax = retval == decmax;
190        retval *= 10;
191        retval += c - '0';
192        if (atmax && retval < decmax) return false;
193        if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
194            return false;
195    }
196
197    c = value[last];
198    if (IsDec(c)) {
199
200        if (retval > decmax) return false;
201        bool atmax = retval == decmax;
202        retval *= 10;
203        retval += c - '0';
204        if (atmax && retval < decmax) return false;
205        if (sign && negative) {
206            if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
207                retval >= (T)-signmax)
208                return false;
209            retval = -retval;
210        }
211        else
212            if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
213                return false;
214        return true;
215    }
216
217  multiply:
218    signed long long mult = 1;
219    T val;
220    switch (c) {
221      case 'k':
222      case 'K':
223        if (i != last) return false;
224        mult = 1024;
225        val = signmax / mult;
226        break;
227      case 'm':
228      case 'M':
229        if (i != last) return false;
230        mult = 1024 * 1024;
231        val = signmax / mult;
232        break;
233      case 'g':
234      case 'G':
235        if (i != last) return false;
236        mult = 1024 * 1024 * 1024;
237        val = signmax / mult;
238        break;
239      case 'e':
240      case 'E':
241        if (i >= last) return false;
242
243        mult = 0;
244        for (i++; i <= last; i++) {
245            c = value[i];
246            if (!IsDec(c))
247                return false;
248
249            mult *= 10;
250            mult += c - '0';
251        }
252
253        for (i = 0; i < mult; i++) {
254            if (retval > signmax / 10)
255                return false;
256            retval *= 10;
257            if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
258                return false;
259        }
260        if (sign && negative) {
261            if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
262                retval >= (T)-signmax)
263                return false;
264            retval = -retval;
265        }
266        else
267            if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
268                return false;
269
270        return true;
271
272      default:
273        return false;
274    }
275
276    if (sign && negative)
277        return false;
278
279    if (mult > (unsigned long long)signmax)
280        return false;
281
282    if (retval > val)
283        return false;
284
285    retval *= mult;
286
287    return true;
288}
289
290#define STN(type) \
291template<> \
292bool to_number<type>(const string &value, type &retval) \
293{ return __to_number(value, retval); }
294
295STN(unsigned long long);
296STN(signed long long);
297STN(unsigned long);
298STN(signed long);
299STN(unsigned int);
300STN(signed int);
301STN(unsigned short);
302STN(signed short);
303STN(unsigned char);
304STN(signed char);
305
306template<>
307bool to_number<bool>(const string &value, bool &retval)
308{
309    string lowered = to_lower(value);
310
311    if (value == "0") {
312        retval = false;
313        return true;
314    }
315
316    if (value == "1"){
317        retval = true;
318        return true;
319    }
320
321    if (lowered == "false") {
322        retval = false;
323        return true;
324    }
325
326    if (lowered == "true"){
327        retval = true;
328        return true;
329    }
330
331    if (lowered == "no") {
332        retval = false;
333        return true;
334    }
335
336    if (lowered == "yes"){
337        retval = true;
338        return true;
339    }
340
341    return false;
342}
343