libstr.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "std-includes.h" | ||
| 4 | //ty alcaro | ||
| 5 | extern const unsigned char char_props[256]; | ||
| 6 | 27542374 | static inline int to_lower(unsigned char c) { return c|(char_props[c]&0x20); } | |
| 7 | 308174 | static inline int to_upper(unsigned char c) { return c&~(char_props[c]&0x20); } | |
| 8 | |||
| 9 | 1726556 | inline bool is_space(unsigned char c) { return char_props[c] & 0x80; } // C standard says \f \v are space, but this one disagrees | |
| 10 | 10071544 | inline bool is_digit(unsigned char c) { return char_props[c] & 0x40; } | |
| 11 | 3342 | inline bool is_alpha(unsigned char c) { return char_props[c] & 0x20; } | |
| 12 | 3570 | inline bool is_lower(unsigned char c) { return char_props[c] & 0x04; } | |
| 13 | 4802 | inline bool is_upper(unsigned char c) { return char_props[c] & 0x02; } | |
| 14 | 24626 | inline bool is_alnum(unsigned char c) { return char_props[c] & 0x60; } | |
| 15 | inline bool is_ualpha(unsigned char c) { return char_props[c] & 0x28; } | ||
| 16 | 1339752 | inline bool is_ualnum(unsigned char c) { return char_props[c] & 0x68; } | |
| 17 | 43242 | inline bool is_xdigit(unsigned char c) { return char_props[c] & 0x01; } | |
| 18 | |||
| 19 | 17718659 | inline char *copy(const char *source, int copy_length, char *dest) | |
| 20 | { | ||
| 21 | 17718659 | memmove(dest, source, copy_length*sizeof(char)); | |
| 22 | 17718659 | return dest; | |
| 23 | } | ||
| 24 | |||
| 25 | 879287 | inline int min_val(int a, int b) | |
| 26 | { | ||
| 27 | 879287 | return a > b ? b : a; | |
| 28 | } | ||
| 29 | |||
| 30 | 880145 | inline int bit_round(int v) | |
| 31 | { | ||
| 32 | 880145 | v--; | |
| 33 | 880145 | v |= v >> 1; | |
| 34 | 880145 | v |= v >> 2; | |
| 35 | 880145 | v |= v >> 4; | |
| 36 | 880145 | v |= v >> 8; | |
| 37 | 880145 | v |= v >> 16; | |
| 38 | 880145 | v++; | |
| 39 | 880145 | return v; | |
| 40 | } | ||
| 41 | |||
| 42 | class string { | ||
| 43 | public: | ||
| 44 | 56152365 | const char *data() const | |
| 45 | { | ||
| 46 | 56152365 | return cached_data; | |
| 47 | } | ||
| 48 | |||
| 49 | 1757129 | char *temp_raw() const //things to cleanup and take a look at | |
| 50 | { | ||
| 51 | 1757129 | return cached_data; | |
| 52 | } | ||
| 53 | |||
| 54 | 54865506 | char *raw() const | |
| 55 | { | ||
| 56 | 54865506 | return cached_data; | |
| 57 | } | ||
| 58 | |||
| 59 | 54308280 | int length() const | |
| 60 | { | ||
| 61 | 54308280 | return is_inlined() ? inlined.len : allocated.len; | |
| 62 | } | ||
| 63 | |||
| 64 | 28280835 | void set_length(int length) | |
| 65 | { | ||
| 66 | 28280835 | if(length > max_inline_length_){ | |
| 67 | 3510911 | inlined.len = (unsigned char)-1; | |
| 68 | 3510911 | allocated.len = length; | |
| 69 | }else{ | ||
| 70 | 24769924 | inlined.len = length; | |
| 71 | } | ||
| 72 | 28280835 | } | |
| 73 | |||
| 74 | 1747442 | void truncate(int newlen) | |
| 75 | { | ||
| 76 | 1747442 | resize(newlen); | |
| 77 | 1747442 | } | |
| 78 | |||
| 79 | 5578354 | void assign(const char * newstr) | |
| 80 | { | ||
| 81 | 5578354 | if (!newstr) newstr = ""; | |
| 82 | 5578354 | assign(newstr, strlen(newstr)); | |
| 83 | 5578354 | } | |
| 84 | |||
| 85 | 5894551 | void assign(const string &newstr) | |
| 86 | { | ||
| 87 | 5894551 | assign(newstr, newstr.length()); | |
| 88 | 5894551 | } | |
| 89 | |||
| 90 | 15917271 | void assign(const char * newstr, int end) | |
| 91 | { | ||
| 92 | 15917271 | resize(end); | |
| 93 | 15917271 | copy(newstr, length(), raw()); | |
| 94 | 15917271 | } | |
| 95 | |||
| 96 | |||
| 97 | 1103738 | string& operator=(const char * newstr) | |
| 98 | { | ||
| 99 | 1103738 | assign(newstr); | |
| 100 | 1103738 | return *this; | |
| 101 | } | ||
| 102 | |||
| 103 | 3067700 | string& operator=(const string &newstr) | |
| 104 | { | ||
| 105 | 3067700 | assign(newstr); | |
| 106 | 3067700 | return *this; | |
| 107 | } | ||
| 108 | |||
| 109 | 875074 | string& operator+=(const string& other) | |
| 110 | { | ||
| 111 | 875074 | int current_end = length(); | |
| 112 | 875074 | resize(length() + other.length()); | |
| 113 | 875074 | copy(other.data(), other.length(), raw() + current_end); | |
| 114 | 875074 | return *this; | |
| 115 | } | ||
| 116 | |||
| 117 | 46332 | string& operator+=(const char *other) | |
| 118 | { | ||
| 119 | 46332 | int current_end = length(); | |
| 120 | 46332 | int otherlen=(int)strlen(other); | |
| 121 | 46332 | resize(length() + otherlen); | |
| 122 | 46332 | copy(other, otherlen, raw() + current_end); | |
| 123 | 46332 | return *this; | |
| 124 | } | ||
| 125 | |||
| 126 | 9693089 | string& operator+=(char c) | |
| 127 | { | ||
| 128 | 9693089 | resize(length() + 1); | |
| 129 | 9693089 | raw()[length() - 1] = c; | |
| 130 | 9693089 | return *this; | |
| 131 | } | ||
| 132 | |||
| 133 | string operator+(char right) const | ||
| 134 | { | ||
| 135 | string ret=*this; | ||
| 136 | ret+=right; | ||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | |||
| 140 | 44300 | string operator+(const char * right) const | |
| 141 | { | ||
| 142 | 44300 | string ret=*this; | |
| 143 | 44300 | ret+=right; | |
| 144 | 44300 | return ret; | |
| 145 | ✗ | } | |
| 146 | |||
| 147 | 5460 | bool operator==(const char * right) const | |
| 148 | { | ||
| 149 | 5460 | return !strcmp(data(), right); | |
| 150 | } | ||
| 151 | |||
| 152 | 104 | bool operator==(const string& right) const | |
| 153 | { | ||
| 154 | 104 | return !strcmp(data(), right.data()); | |
| 155 | } | ||
| 156 | |||
| 157 | 1674 | bool operator!=(const char * right) const | |
| 158 | { | ||
| 159 | 1674 | return (strcmp(data(), right) != 0); | |
| 160 | } | ||
| 161 | |||
| 162 | bool operator!=(const string& right) const | ||
| 163 | { | ||
| 164 | return (strcmp(data(), right.data()) != 0); | ||
| 165 | } | ||
| 166 | |||
| 167 | 18114720 | operator const char*() const | |
| 168 | { | ||
| 169 | 18114720 | return data(); | |
| 170 | } | ||
| 171 | |||
| 172 | 429710 | explicit operator bool() const | |
| 173 | { | ||
| 174 | 429710 | return length(); | |
| 175 | } | ||
| 176 | |||
| 177 | 16712304 | string() | |
| 178 | 16712304 | { | |
| 179 | //todo reduce I know this isn't all needed | ||
| 180 | 16712304 | allocated.bufferlen = 0; | |
| 181 | 16712304 | allocated.str = 0; | |
| 182 | 16712304 | allocated.len = 0; | |
| 183 | 16712304 | inlined.len = 0; | |
| 184 | 16712304 | cached_data = inlined.str; | |
| 185 | 16712304 | next_resize = max_inline_length_+1; | |
| 186 | |||
| 187 | 16712304 | } | |
| 188 | 4003466 | string(const char * newstr) : string() | |
| 189 | { | ||
| 190 | 4003466 | assign(newstr); | |
| 191 | 4003466 | } | |
| 192 | 2616164 | string(const char * newstr, int newlen) : string() | |
| 193 | { | ||
| 194 | 2616164 | assign(newstr, newlen); | |
| 195 | 2616164 | } | |
| 196 | 471150 | string(const string& old) : string() | |
| 197 | { | ||
| 198 | 471150 | assign(old.data()); | |
| 199 | 471150 | } | |
| 200 | |||
| 201 | 1110 | string(string &&move) : string() | |
| 202 | { | ||
| 203 | 1110 | *this = move; | |
| 204 | 1110 | } | |
| 205 | |||
| 206 | 2828478 | string& operator=(string&& move) | |
| 207 | { | ||
| 208 | 2828478 | if(!is_inlined()) free(allocated.str); | |
| 209 | 2828478 | if(!move.is_inlined()){ | |
| 210 | 1627 | allocated.str = move.allocated.str; | |
| 211 | 1627 | allocated.bufferlen = move.allocated.bufferlen; | |
| 212 | 1627 | set_length(move.allocated.len); | |
| 213 | |||
| 214 | 1627 | move.inlined.len = 0; | |
| 215 | 1627 | move.inlined.str[0] = 0; | |
| 216 | 1627 | cached_data = allocated.str; | |
| 217 | 1627 | next_resize = move.next_resize; | |
| 218 | |||
| 219 | }else{ | ||
| 220 | 2826851 | inlined.len = 0; | |
| 221 | 2826851 | cached_data = inlined.str; | |
| 222 | 2826851 | next_resize = max_inline_length_+1; | |
| 223 | 2826851 | assign(move); | |
| 224 | } | ||
| 225 | 2828478 | return *this; | |
| 226 | } | ||
| 227 | |||
| 228 | 16681167 | ~string() | |
| 229 | { | ||
| 230 | 16681167 | if(!is_inlined()){ | |
| 231 | 877629 | free(allocated.str); | |
| 232 | } | ||
| 233 | 16681167 | } | |
| 234 | |||
| 235 | string& replace(const char * instr, const char * outstr, bool all=true); | ||
| 236 | string& qreplace(const char * instr, const char * outstr, bool all=true); | ||
| 237 | |||
| 238 | #ifdef SERIALIZER | ||
| 239 | void serialize(serializer & s) | ||
| 240 | { | ||
| 241 | s(str, allocated.bufferlen); | ||
| 242 | set_length(strlen(str)); | ||
| 243 | } | ||
| 244 | #endif | ||
| 245 | #define SERIALIZER_BANNED | ||
| 246 | |||
| 247 | private: | ||
| 248 | static const int scale_factor = 3; //scale sso | ||
| 249 | static const int max_inline_length_ = ((sizeof(char *) + sizeof(int) * 2) * scale_factor) - 2; | ||
| 250 | char *cached_data; | ||
| 251 | int next_resize; | ||
| 252 | struct si{ | ||
| 253 | char str[max_inline_length_ + 1]; | ||
| 254 | unsigned char len; | ||
| 255 | }; | ||
| 256 | |||
| 257 | struct sa{ | ||
| 258 | char *str; | ||
| 259 | int len; | ||
| 260 | int bufferlen ; | ||
| 261 | }; | ||
| 262 | union{ | ||
| 263 | si inlined; | ||
| 264 | sa allocated; | ||
| 265 | }; | ||
| 266 | |||
| 267 | |||
| 268 | 28279208 | void resize(int new_length) | |
| 269 | { | ||
| 270 | 28279208 | const char *old_data = data(); | |
| 271 | 28279208 | if(new_length >= next_resize || (!is_inlined() && new_length <= max_inline_length_)) { | |
| 272 | 880840 | if(new_length > max_inline_length_ && (is_inlined() || allocated.bufferlen <= new_length)){ //SSO or big to big | |
| 273 | 880145 | int new_size = bit_round(new_length + 1); | |
| 274 | 880145 | if(old_data == inlined.str){ | |
| 275 | 879287 | allocated.str = copy(old_data, min_val(length(), new_length), (char *)malloc(new_size)); | |
| 276 | }else{ | ||
| 277 | 858 | allocated.str = (char *)realloc(allocated.str, new_size); | |
| 278 | 858 | old_data = inlined.str; //this will prevent freeing a dead realloc ptr | |
| 279 | } | ||
| 280 | 880145 | allocated.bufferlen = new_size; | |
| 281 | 880145 | cached_data = allocated.str; | |
| 282 | 880145 | next_resize = allocated.bufferlen; | |
| 283 | 695 | }else if(length() > max_inline_length_ && new_length <= max_inline_length_){ //big to SSO | |
| 284 | 695 | copy(old_data, new_length, inlined.str); | |
| 285 | 695 | cached_data = inlined.str; | |
| 286 | 695 | next_resize = max_inline_length_+1; | |
| 287 | } | ||
| 288 | 880840 | if(old_data != inlined.str && old_data != data()){ | |
| 289 | 695 | free((char *)old_data); | |
| 290 | } | ||
| 291 | } | ||
| 292 | 28279208 | set_length(new_length); | |
| 293 | |||
| 294 | 28279208 | raw()[new_length] = 0; //always ensure null terminator | |
| 295 | 28279208 | } | |
| 296 | |||
| 297 | 104925611 | bool is_inlined() const | |
| 298 | { | ||
| 299 | 104925611 | return inlined.len != (unsigned char)-1; | |
| 300 | } | ||
| 301 | }; | ||
| 302 | #define STR (string) | ||
| 303 | |||
| 304 | char * readfile(const char * fname, const char * basepath); | ||
| 305 | char * readfilenative(const char * fname); | ||
| 306 | bool readfile(const char * fname, const char * basepath, char ** data, int * len);//if you want an uchar*, cast it | ||
| 307 | char ** nsplit(char * str, const char * key, int maxlen, int * len); | ||
| 308 | char ** qnsplit(char * str, const char * key, int maxlen, int * len); | ||
| 309 | char ** qpnsplit(char * str, const char * key, int maxlen, int * len); | ||
| 310 | 1190 | inline char ** split(char * str, const char * key, int * len= nullptr) { return nsplit(str, key, 0, len); } | |
| 311 | 1749348 | inline char ** qsplit(char * str, const char * key, int * len= nullptr) { return qnsplit(str, key, 0, len); } | |
| 312 | 219998 | inline char ** qpsplit(char * str, const char * key, int * len= nullptr) { return qpnsplit(str, key, 0, len); } | |
| 313 | inline char ** split1(char * str, const char * key, int * len= nullptr) { return nsplit(str, key, 2, len); } | ||
| 314 | inline char ** qsplit1(char * str, const char * key, int * len= nullptr) { return qnsplit(str, key, 2, len); } | ||
| 315 | inline char ** qpsplit1(char * str, const char * key, int * len= nullptr) { return qpnsplit(str, key, 2, len); } | ||
| 316 | //void replace(string& str, const char * instr, const char * outstr, bool all); | ||
| 317 | //void qreplace(string& str, const char * instr, const char * outstr, bool all); | ||
| 318 | bool confirmquotes(const char * str); | ||
| 319 | bool confirmqpar(const char * str); | ||
| 320 | char* strqpchr(const char* str, char key); | ||
| 321 | char* strqpstr(const char* str, const char* key); | ||
| 322 | |||
| 323 | ✗ | inline string hex(unsigned int value) | |
| 324 | { | ||
| 325 | ✗ | char buffer[64]; | |
| 326 | if(0); | ||
| 327 | ✗ | else if (value<=0x000000FF) sprintf(buffer, "%.2X", value); | |
| 328 | ✗ | else if (value<=0x0000FFFF) sprintf(buffer, "%.4X", value); | |
| 329 | ✗ | else if (value<=0x00FFFFFF) sprintf(buffer, "%.6X", value); | |
| 330 | ✗ | else sprintf(buffer, "%.8X", value); | |
| 331 | ✗ | return buffer; | |
| 332 | } | ||
| 333 | |||
| 334 | inline string hex(unsigned int value, int width) | ||
| 335 | { | ||
| 336 | char buffer[64]; | ||
| 337 | sprintf(buffer, "%.*X", width, value); | ||
| 338 | return buffer; | ||
| 339 | } | ||
| 340 | |||
| 341 | inline string hex0(unsigned int value) | ||
| 342 | { | ||
| 343 | char buffer[64]; | ||
| 344 | sprintf(buffer, "%X", value); | ||
| 345 | return buffer; | ||
| 346 | } | ||
| 347 | |||
| 348 | ✗ | inline string hex2(unsigned int value) | |
| 349 | { | ||
| 350 | ✗ | char buffer[64]; | |
| 351 | ✗ | sprintf(buffer, "%.2X", value); | |
| 352 | ✗ | return buffer; | |
| 353 | } | ||
| 354 | |||
| 355 | inline string hex3(unsigned int value) | ||
| 356 | { | ||
| 357 | char buffer[64]; | ||
| 358 | sprintf(buffer, "%.3X", value); | ||
| 359 | return buffer; | ||
| 360 | } | ||
| 361 | |||
| 362 | ✗ | inline string hex4(unsigned int value) | |
| 363 | { | ||
| 364 | ✗ | char buffer[64]; | |
| 365 | ✗ | sprintf(buffer, "%.4X", value); | |
| 366 | ✗ | return buffer; | |
| 367 | } | ||
| 368 | |||
| 369 | inline string hex5(unsigned int value) | ||
| 370 | { | ||
| 371 | char buffer[64]; | ||
| 372 | sprintf(buffer, "%.5X", value); | ||
| 373 | return buffer; | ||
| 374 | } | ||
| 375 | |||
| 376 | 2 | inline string hex6(unsigned int value) | |
| 377 | { | ||
| 378 | 1 | char buffer[64]; | |
| 379 | 2 | sprintf(buffer, "%.6X", value); | |
| 380 | 4 | return buffer; | |
| 381 | } | ||
| 382 | |||
| 383 | ✗ | inline string hex8(unsigned int value) | |
| 384 | { | ||
| 385 | ✗ | char buffer[64]; | |
| 386 | ✗ | sprintf(buffer, "%.8X", value); | |
| 387 | ✗ | return buffer; | |
| 388 | } | ||
| 389 | |||
| 390 | 1754 | inline string dec(int value) | |
| 391 | { | ||
| 392 | 877 | char buffer[64]; | |
| 393 | 1754 | sprintf(buffer, "%i", value); | |
| 394 | 3508 | return buffer; | |
| 395 | } | ||
| 396 | |||
| 397 | 211206 | inline string ftostr(double value) | |
| 398 | { | ||
| 399 | // randomdude999: With 100 digits of precision, the buffer needs to be approx. 311+100, | ||
| 400 | // but let's be safe here https://stackoverflow.com/questions/7235456 | ||
| 401 | 105603 | char rval[512]; | |
| 402 | // RPG Hacker: Ridiculously high precision, I know, but we're working with doubles | ||
| 403 | // here and can afford it, so no need to waste any precision | ||
| 404 | 211206 | sprintf(rval, "%.100f", value); | |
| 405 | 211206 | if (strchr(rval, '.'))//nuke useless zeroes | |
| 406 | { | ||
| 407 | 211206 | char * end=strrchr(rval, '\0')-1; | |
| 408 | 21331458 | while (*end=='0') | |
| 409 | { | ||
| 410 | 21120252 | *end='\0'; | |
| 411 | 21120252 | end--; | |
| 412 | } | ||
| 413 | 211206 | if (*end=='.') *end='\0'; | |
| 414 | } | ||
| 415 | 422412 | return rval; | |
| 416 | } | ||
| 417 | |||
| 418 | // Same as above, but with variable precision | ||
| 419 | 18 | inline string ftostrvar(double value, int precision) | |
| 420 | { | ||
| 421 | 18 | int clampedprecision = precision; | |
| 422 | 18 | if (clampedprecision < 0) clampedprecision = 0; | |
| 423 | 18 | if (clampedprecision > 100) clampedprecision = 100; | |
| 424 | |||
| 425 | // see above | ||
| 426 | 9 | char rval[512]; | |
| 427 | 18 | sprintf(rval, "%.*f", clampedprecision, (double)value); | |
| 428 | 18 | if (strchr(rval, '.'))//nuke useless zeroes | |
| 429 | { | ||
| 430 | 16 | char * end = strrchr(rval, '\0') - 1; | |
| 431 | 62 | while (*end == '0') | |
| 432 | { | ||
| 433 | 46 | *end = '\0'; | |
| 434 | 46 | end--; | |
| 435 | } | ||
| 436 | 16 | if (*end == '.') *end = '\0'; | |
| 437 | } | ||
| 438 | 36 | return rval; | |
| 439 | } | ||
| 440 | |||
| 441 | 2818716 | inline bool stribegin(const char * str, const char * key) | |
| 442 | { | ||
| 443 | 4300740 | for (int i=0;key[i];i++) | |
| 444 | { | ||
| 445 | 4075376 | if (to_lower(str[i])!=to_lower(key[i])) return false; | |
| 446 | } | ||
| 447 | 225364 | return true; | |
| 448 | } | ||
| 449 | |||
| 450 | 13924 | inline bool striend(const char * str, const char * key) | |
| 451 | { | ||
| 452 | 13924 | const char * keyend=strrchr(key, '\0'); | |
| 453 | 13924 | const char * strend=strrchr(str, '\0'); | |
| 454 | 18556 | while (key!=keyend) | |
| 455 | { | ||
| 456 | 15690 | keyend--; | |
| 457 | 15690 | strend--; | |
| 458 | 15690 | if (to_lower(*strend)!=to_lower(*keyend)) return false; | |
| 459 | } | ||
| 460 | 2866 | return true; | |
| 461 | } | ||
| 462 | |||
| 463 | 271516 | inline bool stricmpwithupper(const char *word1, const char *word2) | |
| 464 | { | ||
| 465 | 317824 | while(*word2) | |
| 466 | { | ||
| 467 | 308174 | if(to_upper(*word1++) != *word2++) return true; | |
| 468 | } | ||
| 469 | 9650 | return *word1; | |
| 470 | } | ||
| 471 | |||
| 472 | 10695086 | inline bool stricmpwithlower(const char *word1, const char *word2) | |
| 473 | { | ||
| 474 | 20917304 | while(*word2) | |
| 475 | { | ||
| 476 | 19213330 | if(to_lower(*word1++) != *word2++) return true; | |
| 477 | } | ||
| 478 | 1703974 | return *word1; | |
| 479 | } | ||
| 480 | |||
| 481 | //function: return the string without quotes around it, if any exists | ||
| 482 | //if they don't exist, return it unaltered | ||
| 483 | //it is not guaranteed to return str | ||
| 484 | //it is not guaranteed to not edit str | ||
| 485 | //the input must be freed even though it's garbage, the output must not | ||
| 486 | 1368 | inline const char * dequote(char * str) | |
| 487 | { | ||
| 488 | 1368 | if (*str!='"') return str; | |
| 489 | 1284 | int inpos=1; | |
| 490 | 1284 | int outpos=0; | |
| 491 | while (true) | ||
| 492 | { | ||
| 493 | 15494 | if (str[inpos]=='"') | |
| 494 | { | ||
| 495 | 1428 | if (str[inpos+1]=='"') inpos++; | |
| 496 | 1284 | else if (str[inpos+1]=='\0') break; | |
| 497 | ✗ | else return nullptr; | |
| 498 | } | ||
| 499 | 14210 | if (!str[inpos]) return nullptr; | |
| 500 | 14210 | str[outpos++]=str[inpos++]; | |
| 501 | } | ||
| 502 | 1284 | str[outpos]=0; | |
| 503 | 1284 | return str; | |
| 504 | } | ||
| 505 | |||
| 506 | 24832 | inline char * strqchr(const char * str, char key) | |
| 507 | { | ||
| 508 | 199036 | while (*str != '\0') | |
| 509 | { | ||
| 510 | 180022 | if (*str == key) { return const_cast<char*>(str); } | |
| 511 | 174208 | else if (*str == '"' || *str == '\'') | |
| 512 | { | ||
| 513 | // Special case hack for ''', which is currently our official way of handling the ' character. | ||
| 514 | // Even though it really stinks. | ||
| 515 | 976 | if (str[0] == '\'' && str[1] == '\'' && str[2] == '\'') { str += 2; } | |
| 516 | else | ||
| 517 | { | ||
| 518 | 968 | char delimiter = *str; | |
| 519 | |||
| 520 | do | ||
| 521 | { | ||
| 522 | 13396 | str++; | |
| 523 | |||
| 524 | // If we want to support backslash escapes, we'll have to add that right here. | ||
| 525 | 13396 | } while (*str != delimiter && *str != '\0'); | |
| 526 | |||
| 527 | // This feels like a superfluous check, but I can't really find a clean way to avoid it. | ||
| 528 | 968 | if (*str == '\0') { return nullptr; } | |
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | 174204 | str++; | |
| 533 | } | ||
| 534 | |||
| 535 | 19014 | return nullptr; | |
| 536 | } | ||
| 537 | |||
| 538 | // RPG Hacker: WOW, these functions are poopy! | ||
| 539 | 13180 | inline char * strqrchr(const char * str, char key) | |
| 540 | { | ||
| 541 | 13180 | const char * ret= nullptr; | |
| 542 | 106316 | while (*str) | |
| 543 | { | ||
| 544 | 93136 | if (*str=='"' || *str=='\'') | |
| 545 | { | ||
| 546 | 862 | char token = *str; | |
| 547 | |||
| 548 | 862 | str++; | |
| 549 | |||
| 550 | // Special case hack for ''' | ||
| 551 | 862 | if (str[0] == '\'' && str[1] == '\'') { str += 2; } | |
| 552 | else | ||
| 553 | { | ||
| 554 | 9342 | while (*str != token) | |
| 555 | { | ||
| 556 | 8484 | if (!*str) return nullptr; | |
| 557 | 8484 | str++; | |
| 558 | } | ||
| 559 | 858 | str++; | |
| 560 | } | ||
| 561 | 862 | } | |
| 562 | else | ||
| 563 | { | ||
| 564 | 92274 | if (*str==key) ret=str; | |
| 565 | 92274 | str++; | |
| 566 | } | ||
| 567 | } | ||
| 568 | 13180 | return const_cast<char*>(ret); | |
| 569 | } | ||
| 570 | |||
| 571 | 2760 | inline string substr(const char * str, int len) | |
| 572 | { | ||
| 573 | 2760 | return string(str, len); | |
| 574 | } | ||
| 575 | |||
| 576 | string &strip_prefix(string &str, char c, bool multi=false); | ||
| 577 | string &strip_suffix(string &str, char c, bool multi=false); | ||
| 578 | string &strip_both(string &str, char c, bool multi=false); | ||
| 579 | string &strip_whitespace(string &str); | ||
| 580 | |||
| 581 | char * itrim(char * str, const char * left, const char * right, bool multi=false); | ||
| 582 | string &itrim(string &str, const char * left, const char * right, bool multi=false); | ||
| 583 | |||
| 584 | inline string &upper(string &old) | ||
| 585 | { | ||
| 586 | int length = old.length(); | ||
| 587 | for (int i=0;i<length;i++) old.raw()[i]=(char)to_upper(old.data()[i]); | ||
| 588 | return old; | ||
| 589 | } | ||
| 590 | |||
| 591 | 1430 | inline string &lower(string &old) | |
| 592 | { | ||
| 593 | 1430 | int length = old.length(); | |
| 594 | 55950 | for (int i=0;i<length;i++) old.raw()[i]=(char)to_lower(old.data()[i]); | |
| 595 | 1430 | return old; | |
| 596 | } | ||
| 597 | |||
| 598 | inline const char * stristr(const char * string, const char * pattern) | ||
| 599 | { | ||
| 600 | if (!*pattern) return string; | ||
| 601 | const char * pptr; | ||
| 602 | const char * sptr; | ||
| 603 | const char * start; | ||
| 604 | for (start=string;*start!=0;start++) | ||
| 605 | { | ||
| 606 | for (;(*start && (to_lower(*start)!=to_lower(*pattern)));start++); | ||
| 607 | if (!*start) return nullptr; | ||
| 608 | pptr=pattern; | ||
| 609 | sptr=start; | ||
| 610 | while (to_lower(*sptr)==to_lower(*pptr)) | ||
| 611 | { | ||
| 612 | sptr++; | ||
| 613 | pptr++; | ||
| 614 | if (!*pptr) return start; | ||
| 615 | } | ||
| 616 | } | ||
| 617 | return nullptr; | ||
| 618 | } | ||
| 619 | |||
| 620 | |||
| 621 | |||
| 622 | // Returns number of connected lines - 1 | ||
| 623 | template<typename stringarraytype> | ||
| 624 | 873878 | inline int getconnectedlines(stringarraytype& lines, int startline, string& out) | |
| 625 | { | ||
| 626 | 873878 | out = string(""); | |
| 627 | 873878 | int count = 1; | |
| 628 | |||
| 629 | 873896 | for (int i = startline; lines[i]; i++) | |
| 630 | { | ||
| 631 | // The line should already be stripped of any comments at this point | ||
| 632 | 873896 | int linestartpos = (int)strlen(lines[i]); | |
| 633 | |||
| 634 | 873896 | bool found = false; | |
| 635 | |||
| 636 | 1737258 | for (int j = linestartpos; j > 0; j--) | |
| 637 | { | ||
| 638 | 1726544 | if (!is_space(lines[i][j]) && lines[i][j] != '\0' && lines[i][j] != ';') | |
| 639 | { | ||
| 640 | 863182 | if (lines[i][j] == '\\') | |
| 641 | { | ||
| 642 | 18 | count++; | |
| 643 | 18 | out += string(lines[i], j); | |
| 644 | 18 | found = true; | |
| 645 | 18 | break; | |
| 646 | } | ||
| 647 | else | ||
| 648 | { | ||
| 649 | 863164 | out += string(lines[i], j + 1); | |
| 650 | 863164 | return count - 1; | |
| 651 | } | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | 10732 | if (!found) | |
| 656 | { | ||
| 657 | 10714 | out += string(lines[i], 1); | |
| 658 | 10714 | return count - 1; | |
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 662 | ✗ | return count - 1; | |
| 663 | } | ||
| 664 |