str.cc revision 1793
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