libstr.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "std-includes.h" | ||
| 4 | #include <cstdint> | ||
| 5 | #include <cstring> | ||
| 6 | #include <utility> | ||
| 7 | #include <string_view> | ||
| 8 | #include <cinttypes> | ||
| 9 | |||
| 10 | //ty alcaro | ||
| 11 | extern const unsigned char char_props[256]; | ||
| 12 | 1793561 | static inline int to_lower(unsigned char c) { return c|(char_props[c]&0x20); } | |
| 13 | static inline int to_upper(unsigned char c) { return c&~(char_props[c]&0x20); } | ||
| 14 | |||
| 15 | 274435 | inline bool is_space(unsigned char c) { return char_props[c] & 0x80; } // C standard says \f \v are space, but this one disagrees | |
| 16 | // TODO is this opaque table lookup really faster than c >= '0' && c <= '9'? | ||
| 17 | 47326 | inline bool is_digit(unsigned char c) { return char_props[c] & 0x40; } | |
| 18 | inline bool is_alpha(unsigned char c) { return char_props[c] & 0x20; } | ||
| 19 | ✗ | inline bool is_lower(unsigned char c) { return char_props[c] & 0x04; } | |
| 20 | 106 | inline bool is_upper(unsigned char c) { return char_props[c] & 0x02; } | |
| 21 | inline bool is_alnum(unsigned char c) { return char_props[c] & 0x60; } | ||
| 22 | 16478 | inline bool is_ualpha(unsigned char c) { return char_props[c] & 0x28; } | |
| 23 | 122467 | inline bool is_ualnum(unsigned char c) { return char_props[c] & 0x68; } | |
| 24 | 7297 | inline bool is_xdigit(unsigned char c) { return char_props[c] & 0x01; } | |
| 25 | |||
| 26 | 1089485 | inline char *copy(const char *source, int copy_length, char *dest) | |
| 27 | { | ||
| 28 | 1089485 | memcpy(dest, source, copy_length*sizeof(char)); | |
| 29 | 1089485 | return dest; | |
| 30 | } | ||
| 31 | |||
| 32 | class string { | ||
| 33 | public: | ||
| 34 | 4831246 | const char *data() const | |
| 35 | { | ||
| 36 | 4831246 | return data_ptr; | |
| 37 | } | ||
| 38 | |||
| 39 | 86526 | char *temp_raw() const //things to cleanup and take a look at | |
| 40 | { | ||
| 41 | 86526 | return data_ptr; | |
| 42 | } | ||
| 43 | |||
| 44 | 872261 | char *raw() const | |
| 45 | { | ||
| 46 | 872261 | return data_ptr; | |
| 47 | } | ||
| 48 | |||
| 49 | 4832351 | int length() const | |
| 50 | { | ||
| 51 | 4832351 | return len; | |
| 52 | } | ||
| 53 | |||
| 54 | 2020043 | void resize(unsigned int new_length) | |
| 55 | { | ||
| 56 | 2020043 | if (new_length > capacity()) { | |
| 57 | 3703 | reallocate_capacity(new_length); | |
| 58 | } | ||
| 59 | |||
| 60 | 2020043 | len = new_length; | |
| 61 | 2020043 | data_ptr[new_length] = 0; //always ensure null terminator | |
| 62 | 2020043 | } | |
| 63 | |||
| 64 | 804 | void truncate(int newlen) | |
| 65 | { | ||
| 66 | 804 | resize(newlen); | |
| 67 | 804 | } | |
| 68 | |||
| 69 | 211380 | void assign(const char * newstr) | |
| 70 | { | ||
| 71 | 211380 | if (!newstr) newstr = ""; | |
| 72 | 211380 | assign(newstr, strlen(newstr)); | |
| 73 | 211380 | } | |
| 74 | |||
| 75 | 289155 | void assign(const string &newstr) | |
| 76 | { | ||
| 77 | 289155 | assign(newstr.data(), newstr.length()); | |
| 78 | 289155 | } | |
| 79 | |||
| 80 | 901309 | void assign(const char * newstr, int end) | |
| 81 | { | ||
| 82 | 901309 | resize(end); | |
| 83 | 901309 | copy(newstr, end, data_ptr); | |
| 84 | 901309 | } | |
| 85 | |||
| 86 | |||
| 87 | 12734 | string& operator=(const char * newstr) | |
| 88 | { | ||
| 89 | 12734 | assign(newstr); | |
| 90 | 12734 | return *this; | |
| 91 | } | ||
| 92 | |||
| 93 | 289155 | string& operator=(const string &newstr) | |
| 94 | { | ||
| 95 | 289155 | assign(newstr); | |
| 96 | 289155 | return *this; | |
| 97 | } | ||
| 98 | |||
| 99 | string& append(const string& other, int start, int end) | ||
| 100 | { | ||
| 101 | int current_end = length(); | ||
| 102 | resize(length() + end - start); | ||
| 103 | copy(other.data() + start, end - start, data_ptr + current_end); | ||
| 104 | return *this; | ||
| 105 | } | ||
| 106 | |||
| 107 | 3632 | string& append(const char *other, int start, int end) | |
| 108 | { | ||
| 109 | 3632 | int current_end = length(); | |
| 110 | 3632 | resize(length() + end - start); | |
| 111 | 3632 | copy(other + start, end - start, data_ptr + current_end); | |
| 112 | 3632 | return *this; | |
| 113 | } | ||
| 114 | |||
| 115 | 64806 | string& operator+=(const string& other) | |
| 116 | { | ||
| 117 | 64806 | int current_end = length(); | |
| 118 | 64806 | resize(length() + other.length()); | |
| 119 | 64806 | copy(other.data(), other.length(), data_ptr + current_end); | |
| 120 | 64806 | return *this; | |
| 121 | } | ||
| 122 | |||
| 123 | 116319 | string& operator+=(const char *other) | |
| 124 | { | ||
| 125 | 116319 | int current_end = length(); | |
| 126 | 116319 | int otherlen=(int)strlen(other); | |
| 127 | 116319 | resize(length() + otherlen); | |
| 128 | 116319 | copy(other, otherlen, data_ptr + current_end); | |
| 129 | 116319 | return *this; | |
| 130 | } | ||
| 131 | |||
| 132 | 933169 | string& operator+=(char c) | |
| 133 | { | ||
| 134 | 933169 | resize(length() + 1); | |
| 135 | 933169 | data_ptr[length() - 1] = c; | |
| 136 | 933169 | return *this; | |
| 137 | } | ||
| 138 | |||
| 139 | string operator+(char right) const | ||
| 140 | { | ||
| 141 | string ret=*this; | ||
| 142 | ret+=right; | ||
| 143 | return ret; | ||
| 144 | } | ||
| 145 | |||
| 146 | 45734 | string operator+(const char * right) const | |
| 147 | { | ||
| 148 | 45734 | string ret=*this; | |
| 149 | 45734 | ret+=right; | |
| 150 | 45734 | return ret; | |
| 151 | ✗ | } | |
| 152 | |||
| 153 | 3080169 | operator const char*() const | |
| 154 | { | ||
| 155 | 3080169 | return data(); | |
| 156 | } | ||
| 157 | |||
| 158 | 10308 | explicit operator bool() const | |
| 159 | { | ||
| 160 | 10308 | return length(); | |
| 161 | } | ||
| 162 | |||
| 163 | 1119565 | string() | |
| 164 | 1119565 | { | |
| 165 | 1119565 | data_ptr = inlined.data; | |
| 166 | 1119565 | len = 0; | |
| 167 | 1119565 | inlined.data[0] = '\0'; | |
| 168 | 1119565 | } | |
| 169 | 191458 | string(const char * newstr) : string() | |
| 170 | { | ||
| 171 | 191458 | assign(newstr); | |
| 172 | 191458 | } | |
| 173 | 84575 | string(const char * newstr, int newlen) : string() | |
| 174 | { | ||
| 175 | 84575 | assign(newstr, newlen); | |
| 176 | 84575 | } | |
| 177 | 270195 | string(const string& old) : string() | |
| 178 | { | ||
| 179 | 270195 | assign(old.data(), old.length()); | |
| 180 | 270195 | } | |
| 181 | |||
| 182 | 25916 | string(string &&move) noexcept : string() | |
| 183 | { | ||
| 184 | 25916 | *this = move; | |
| 185 | 25916 | } | |
| 186 | |||
| 187 | 113046 | string& operator=(string&& other) noexcept | |
| 188 | { | ||
| 189 | 113046 | if (other.is_inlined()) { | |
| 190 | // No resources to steal so just do a normal assignment | ||
| 191 | 112879 | *this = other; | |
| 192 | } else { | ||
| 193 | 167 | if (is_inlined()) { | |
| 194 | 125 | data_ptr = other.data_ptr; | |
| 195 | 125 | other.data_ptr = 0; | |
| 196 | } else { | ||
| 197 | // Give our old allocation back so other can free it for us | ||
| 198 | 42 | std::swap(data_ptr, other.data_ptr); | |
| 199 | } | ||
| 200 | 167 | len = other.len; | |
| 201 | 167 | allocated = other.allocated; | |
| 202 | } | ||
| 203 | 113046 | return *this; | |
| 204 | } | ||
| 205 | |||
| 206 | 1070091 | ~string() | |
| 207 | { | ||
| 208 | 1070091 | if(!is_inlined()){ | |
| 209 | 3538 | free(data_ptr); | |
| 210 | } | ||
| 211 | 1070091 | } | |
| 212 | |||
| 213 | //maybe these should return refs to chain. but also good not to encourage chaining | ||
| 214 | 10 | void strip_prefix(char c) | |
| 215 | { | ||
| 216 | 10 | if(data()[0] == c){ | |
| 217 | 4 | std::memmove(data_ptr, data_ptr + 1, length() - 1); | |
| 218 | 4 | resize(length() - 1); | |
| 219 | } | ||
| 220 | 10 | } | |
| 221 | |||
| 222 | void strip_suffix(char c) | ||
| 223 | { | ||
| 224 | if (data()[length() - 1] == c) { | ||
| 225 | truncate(length() - 1); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | string& qreplace(const char * instr, const char * outstr); | ||
| 230 | string& qnormalize(); | ||
| 231 | |||
| 232 | // RPG Hacker: My hack shmeck to get around no longer supporting text mode. | ||
| 233 | // Symbol files are currently the only thing that use text mode, anyways, and I don't even know | ||
| 234 | // if the emulators that read them care about line endings. | ||
| 235 | ✗ | string& convert_line_endings_to_native() | |
| 236 | { | ||
| 237 | #if defined(windows) | ||
| 238 | // RPG Hacker: This is quite stinky, but doing the replacement directly will lead to a dead-lock. | ||
| 239 | // \x08 = backspace should never appear inside a string, so I'm abusing it here. | ||
| 240 | ✗ | return qreplace("\n", "\x08").qreplace("\x08", "\r\n"); | |
| 241 | #else | ||
| 242 | ✗ | return *this; | |
| 243 | #endif | ||
| 244 | } | ||
| 245 | |||
| 246 | private: | ||
| 247 | static const int scale_factor = 4; //scale sso | ||
| 248 | static const int inline_capacity = ((sizeof(char *) + sizeof(int) * 2) * scale_factor) - 2; | ||
| 249 | |||
| 250 | // Points to a malloc'd data block or to inlined.data | ||
| 251 | char *data_ptr; | ||
| 252 | unsigned int len; | ||
| 253 | union { | ||
| 254 | struct { | ||
| 255 | // Actual allocated capacity is +1 this value, to cover for the terminating NUL | ||
| 256 | unsigned int capacity; | ||
| 257 | } allocated; | ||
| 258 | struct { | ||
| 259 | char data[inline_capacity + 1]; | ||
| 260 | } inlined; | ||
| 261 | }; | ||
| 262 | |||
| 263 | void reallocate_capacity(unsigned int new_length); | ||
| 264 | |||
| 265 | 2020043 | unsigned capacity() const | |
| 266 | { | ||
| 267 | 2020043 | return is_inlined() ? inline_capacity : allocated.capacity; | |
| 268 | } | ||
| 269 | |||
| 270 | 3207050 | bool is_inlined() const | |
| 271 | { | ||
| 272 | 3207050 | return data_ptr == inlined.data; | |
| 273 | } | ||
| 274 | }; | ||
| 275 | #define STR (string) | ||
| 276 | |||
| 277 | #define ASAR_STRCMP_OPERATORS(op) \ | ||
| 278 | inline bool operator op(const string& left, const string& right) { \ | ||
| 279 | return strcmp(left, right) op 0; \ | ||
| 280 | } \ | ||
| 281 | inline bool operator op(const string& left, const char* right) { \ | ||
| 282 | return strcmp(left, right) op 0; \ | ||
| 283 | } \ | ||
| 284 | inline bool operator op(const char* left, const string& right) { \ | ||
| 285 | return strcmp(left, right) op 0; \ | ||
| 286 | } | ||
| 287 | |||
| 288 | 62477 | ASAR_STRCMP_OPERATORS(==) | |
| 289 | 10872 | ASAR_STRCMP_OPERATORS(!=) | |
| 290 | 4 | ASAR_STRCMP_OPERATORS(<) | |
| 291 | ✗ | ASAR_STRCMP_OPERATORS(<=) | |
| 292 | 2 | ASAR_STRCMP_OPERATORS(>) | |
| 293 | 2 | ASAR_STRCMP_OPERATORS(>=) | |
| 294 | #undef ASAR_STRCMP_OPERATORS | ||
| 295 | |||
| 296 | template<> | ||
| 297 | struct std::hash<string> { | ||
| 298 | 65011 | size_t operator()(const ::string& s) const { | |
| 299 | 65011 | return std::hash<std::string_view>()(std::string_view(s.data(), s.length())); | |
| 300 | } | ||
| 301 | }; | ||
| 302 | |||
| 303 | char * readfile(const char * fname, const char * basepath); | ||
| 304 | char * readfilenative(const char * fname); | ||
| 305 | bool readfile(const char * fname, const char * basepath, char ** data, int * len);//if you want an uchar*, cast it | ||
| 306 | char ** split(char * str, char key, int * len= nullptr); | ||
| 307 | char ** qsplit(char * str, char key, int * len= nullptr); | ||
| 308 | char ** qpsplit(char * str, char key, int * len= nullptr); | ||
| 309 | char ** qsplitstr(char * str, const char * key, int * len= nullptr); | ||
| 310 | bool confirmquotes(const char * str); | ||
| 311 | bool confirmqpar(const char * str); | ||
| 312 | char* strqpchr(char* str, char key); | ||
| 313 | char* strqpstr(char* str, const char* key); | ||
| 314 | 1056 | inline const char* strqpchr(const char* str, char key) { return strqpchr(const_cast<char*>(str), key); }; | |
| 315 | 114 | inline const char* strqpstr(const char* str, const char* key) { return strqpstr(const_cast<char*>(str), key); }; | |
| 316 | |||
| 317 | ✗ | inline string hex(unsigned int value) | |
| 318 | { | ||
| 319 | ✗ | char buffer[64]; | |
| 320 | if(0); | ||
| 321 | ✗ | else if (value<=0x000000FF) snprintf(buffer, sizeof(buffer), "%.2X", value); | |
| 322 | ✗ | else if (value<=0x0000FFFF) snprintf(buffer, sizeof(buffer), "%.4X", value); | |
| 323 | ✗ | else if (value<=0x00FFFFFF) snprintf(buffer, sizeof(buffer), "%.6X", value); | |
| 324 | ✗ | else snprintf(buffer, sizeof(buffer), "%.8X", value); | |
| 325 | ✗ | return buffer; | |
| 326 | } | ||
| 327 | |||
| 328 | 2 | inline string hex(unsigned int value, int width) | |
| 329 | { | ||
| 330 | 1 | char buffer[64]; | |
| 331 | 2 | snprintf(buffer, sizeof(buffer), "%.*X", width, value); | |
| 332 | 4 | return buffer; | |
| 333 | } | ||
| 334 | |||
| 335 | 3268 | inline string dec(int64_t value) | |
| 336 | { | ||
| 337 | 1683 | char buffer[64]; | |
| 338 | 3268 | snprintf(buffer, sizeof(buffer), "%" PRId64, value); | |
| 339 | 6536 | return buffer; | |
| 340 | } | ||
| 341 | |||
| 342 | // todo this function sucks, replace with std::to_chars | ||
| 343 | 258 | inline string ftostr(double value) | |
| 344 | { | ||
| 345 | // randomdude999: With 100 digits of precision, the buffer needs to be approx. 311+100, | ||
| 346 | // but let's be safe here https://stackoverflow.com/questions/7235456 | ||
| 347 | 129 | char rval[512]; | |
| 348 | // RPG Hacker: Ridiculously high precision, I know, but we're working with doubles | ||
| 349 | // here and can afford it, so no need to waste any precision | ||
| 350 | 258 | snprintf(rval, sizeof(rval), "%.100f", value); | |
| 351 | 258 | if (strchr(rval, '.'))//nuke useless zeroes | |
| 352 | { | ||
| 353 | 258 | char * end=strrchr(rval, '\0')-1; | |
| 354 | 25710 | while (*end=='0') | |
| 355 | { | ||
| 356 | 25452 | *end='\0'; | |
| 357 | 25452 | end--; | |
| 358 | } | ||
| 359 | 258 | if (*end=='.') *end='\0'; | |
| 360 | } | ||
| 361 | 516 | return rval; | |
| 362 | } | ||
| 363 | |||
| 364 | // Same as above, but with variable precision | ||
| 365 | 20 | inline string ftostrvar(double value, int precision) | |
| 366 | { | ||
| 367 | 20 | int clampedprecision = precision; | |
| 368 | 20 | if (clampedprecision < 0) clampedprecision = 0; | |
| 369 | 20 | if (clampedprecision > 100) clampedprecision = 100; | |
| 370 | |||
| 371 | // see above | ||
| 372 | 10 | char rval[512]; | |
| 373 | 20 | snprintf(rval, sizeof(rval), "%.*f", clampedprecision, (double)value); | |
| 374 | 20 | if (strchr(rval, '.'))//nuke useless zeroes | |
| 375 | { | ||
| 376 | 18 | char * end = strrchr(rval, '\0') - 1; | |
| 377 | 64 | while (*end == '0') | |
| 378 | { | ||
| 379 | 46 | *end = '\0'; | |
| 380 | 46 | end--; | |
| 381 | } | ||
| 382 | 18 | if (*end == '.') *end = '\0'; | |
| 383 | } | ||
| 384 | 40 | return rval; | |
| 385 | } | ||
| 386 | |||
| 387 | 123549 | inline bool stribegin(const char * str, const char * key) | |
| 388 | { | ||
| 389 | 451348 | for (int i=0;key[i];i++) | |
| 390 | { | ||
| 391 | 441476 | if (to_lower(str[i])!=to_lower(key[i])) return false; | |
| 392 | } | ||
| 393 | 9872 | return true; | |
| 394 | } | ||
| 395 | |||
| 396 | inline bool striend(const char * str, const char * key) | ||
| 397 | { | ||
| 398 | const char * keyend=strrchr(key, '\0'); | ||
| 399 | const char * strend=strrchr(str, '\0'); | ||
| 400 | if(keyend-key > strend-str) return false; | ||
| 401 | |||
| 402 | while (key!=keyend) | ||
| 403 | { | ||
| 404 | keyend--; | ||
| 405 | strend--; | ||
| 406 | if (to_lower(*strend)!=to_lower(*keyend)) return false; | ||
| 407 | } | ||
| 408 | return true; | ||
| 409 | } | ||
| 410 | |||
| 411 | inline bool stricmpwithupper(const char *word1, const char *word2) | ||
| 412 | { | ||
| 413 | while(*word2) | ||
| 414 | { | ||
| 415 | if(to_upper(*word1++) != *word2++) return true; | ||
| 416 | } | ||
| 417 | return *word1; | ||
| 418 | } | ||
| 419 | |||
| 420 | 27622 | inline bool stricmpwithlower(const char *word1, const char *word2) | |
| 421 | { | ||
| 422 | 32908 | while(*word2) | |
| 423 | { | ||
| 424 | 32388 | if(to_lower(*word1++) != *word2++) return true; | |
| 425 | } | ||
| 426 | 520 | return *word1; | |
| 427 | } | ||
| 428 | |||
| 429 | //function: return the string without quotes around it, if any exists | ||
| 430 | //if they don't exist, return it unaltered | ||
| 431 | //it is not guaranteed to return str | ||
| 432 | //it is not guaranteed to not edit str | ||
| 433 | //the input must be freed even though it's garbage, the output must not | ||
| 434 | 11527 | inline const char * dequote(char * str) | |
| 435 | { | ||
| 436 | 11527 | if (*str!='"') return str; | |
| 437 | 10759 | char *end = strrchr(str, '"'); | |
| 438 | 10759 | if (end) | |
| 439 | { | ||
| 440 | // make sure the closing quote is at the end of the argument | ||
| 441 | 10759 | if(end[1] != 0) return nullptr; | |
| 442 | 10759 | *end = 0; | |
| 443 | 10759 | char *quote = str+1; | |
| 444 | 10903 | while((quote = strstr(quote, "\"\""))) { | |
| 445 | 144 | memmove(quote, quote+1, strlen(quote)); | |
| 446 | 144 | quote++; | |
| 447 | } | ||
| 448 | 10759 | return str + 1; | |
| 449 | } | ||
| 450 | ✗ | return nullptr; | |
| 451 | } | ||
| 452 | |||
| 453 | 57999 | inline char * strqchr(char * str, char key) | |
| 454 | { | ||
| 455 | 397170 | while (*str != '\0') | |
| 456 | { | ||
| 457 | 377541 | if (*str == key) { return str; } | |
| 458 | 339173 | else if (*str == '"' || *str == '\'') | |
| 459 | { | ||
| 460 | // Special case hack for ''', which is currently our official way of handling the ' character. | ||
| 461 | // Even though it really stinks. | ||
| 462 | 1606 | if (str[0] == '\'' && str[1] == '\'' && str[2] == '\'') { str += 2; } | |
| 463 | else | ||
| 464 | { | ||
| 465 | 1576 | char delimiter = *str; | |
| 466 | |||
| 467 | do | ||
| 468 | { | ||
| 469 | 11242 | str++; | |
| 470 | |||
| 471 | // If we want to support backslash escapes, we'll have to add that right here. | ||
| 472 | 11242 | } while (*str != delimiter && *str != '\0'); | |
| 473 | |||
| 474 | // This feels like a superfluous check, but I can't really find a clean way to avoid it. | ||
| 475 | 1576 | if (*str == '\0') { return nullptr; } | |
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | 339171 | str++; | |
| 480 | } | ||
| 481 | |||
| 482 | 19629 | return nullptr; | |
| 483 | } | ||
| 484 | |||
| 485 | 41324 | inline const char * strqchr(const char * str, char key) { | |
| 486 | 41324 | return strqchr(const_cast<char*>(str), key); | |
| 487 | } | ||
| 488 | |||
| 489 | 2580 | inline string substr(const char * str, int len) | |
| 490 | { | ||
| 491 | 2580 | return string(str, len); | |
| 492 | } | ||
| 493 | |||
| 494 | |||
| 495 | 72717 | inline char *strip_whitespace(char *str) | |
| 496 | { | ||
| 497 | 76220 | while(is_space(*str)) str++; | |
| 498 | 87865 | for(int i = strlen(str) - 1; i >= 0; i--) | |
| 499 | { | ||
| 500 | 64695 | if(!is_space(str[i])) | |
| 501 | { | ||
| 502 | 49547 | str[i + 1] = 0; | |
| 503 | 49547 | return str; | |
| 504 | } | ||
| 505 | } | ||
| 506 | 23170 | return str; | |
| 507 | } | ||
| 508 | 266 | inline void strip_whitespace(string &str) | |
| 509 | { | ||
| 510 | 266 | str = string(strip_whitespace(str.temp_raw())); | |
| 511 | 266 | } | |
| 512 | |||
| 513 | 41264 | inline void grab_until_space(string& to, const char*& from) { | |
| 514 | // i tried to use strchr here as an optimization, but it wasn't even faster.... | ||
| 515 | 41264 | const char* params = strqchr(from, ' '); | |
| 516 | 41264 | if(params) { | |
| 517 | 34076 | to.assign(from, params - from); | |
| 518 | 34076 | from = params+1; | |
| 519 | } else { | ||
| 520 | 7188 | to.assign(from); | |
| 521 | 7188 | from += to.length(); // now from points at a null byte | |
| 522 | } | ||
| 523 | 41264 | } | |
| 524 | |||
| 525 | string &itrim(string &str, const char * left, const char * right); | ||
| 526 | |||
| 527 | 110151 | inline string &lower(string &old) | |
| 528 | { | ||
| 529 | 110151 | int length = old.length(); | |
| 530 | 957772 | for (int i=0;i<length;i++) old.raw()[i]=(char)to_lower(old.data()[i]); | |
| 531 | 110151 | return old; | |
| 532 | } | ||
| 533 | |||
| 534 | |||
| 535 | // Returns number of connected lines - 1 | ||
| 536 | template<typename stringarraytype> | ||
| 537 | 53607 | inline int getconnectedlines(stringarraytype& lines, int startline, string& out) | |
| 538 | { | ||
| 539 | 53607 | int count = 0; | |
| 540 | |||
| 541 | 53625 | for (int i = startline; lines[i]; i++) | |
| 542 | { | ||
| 543 | // The line should already be stripped of any comments at this point | ||
| 544 | 53625 | int linestartpos = (int)strlen(lines[i]); | |
| 545 | |||
| 546 | 53625 | if(linestartpos && lines[i][linestartpos - 1] == '\\') | |
| 547 | { | ||
| 548 | 18 | count++; | |
| 549 | 18 | out += string(lines[i], linestartpos - 1); | |
| 550 | 18 | continue; | |
| 551 | } | ||
| 552 | else | ||
| 553 | { | ||
| 554 | 53607 | out += string(lines[i], linestartpos); | |
| 555 | 53607 | return count; | |
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | ✗ | return count; | |
| 560 | } | ||
| 561 |