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