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