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