Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include "std-includes.h"
4 : : //ty alcaro
5 : : extern const unsigned char char_props[256];
6 : 13602389 : static inline int to_lower(unsigned char c) { return c|(char_props[c]&0x20); }
7 : 63247 : static inline int to_upper(unsigned char c) { return c&~(char_props[c]&0x20); }
8 : :
9 : 1044 : inline bool is_space(unsigned char c) { return char_props[c] & 0x80; } // C standard says \f \v are space, but this one disagrees
10 : 5035284 : inline bool is_digit(unsigned char c) { return char_props[c] & 0x40; }
11 : 1378 : inline bool is_alpha(unsigned char c) { return char_props[c] & 0x20; }
12 : 1470 : inline bool is_lower(unsigned char c) { return char_props[c] & 0x04; }
13 : 1977 : inline bool is_upper(unsigned char c) { return char_props[c] & 0x02; }
14 : 11845 : 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 : 666252 : inline bool is_ualnum(unsigned char c) { return char_props[c] & 0x68; }
17 : 14929 : inline bool is_xdigit(unsigned char c) { return char_props[c] & 0x01; }
18 : :
19 : : inline char *copy(const char *source, int copy_length, char *dest)
20 : : {
21 : 8294127 : memmove(dest, source, copy_length*sizeof(char));
22 : : return dest;
23 : : }
24 : :
25 : : inline int min_val(int a, int b)
26 : : {
27 : : return a > b ? b : a;
28 : : }
29 : :
30 : 4563 : inline int bit_round(int v)
31 : : {
32 : 4563 : v--;
33 : 4563 : v |= v >> 1;
34 : 4563 : v |= v >> 2;
35 : 4563 : v |= v >> 4;
36 : 4563 : v |= v >> 8;
37 : 4563 : v |= v >> 16;
38 : 4563 : v++;
39 : 4563 : return v;
40 : : }
41 : :
42 : : class string {
43 : : public:
44 : : const char *data() const
45 : : {
46 : 6967374 : return cached_data;
47 : : }
48 : :
49 : : char *temp_raw() const //things to cleanup and take a look at
50 : : {
51 : 875298 : return cached_data;
52 : : }
53 : :
54 : : char *raw() const
55 : : {
56 : 27099636 : return cached_data;
57 : : }
58 : :
59 : : int length() const
60 : : {
61 : 25188230 : return is_inlined() ? inlined.len : allocated.len;
62 : : }
63 : :
64 : 13992149 : void set_length(int length)
65 : : {
66 [ + + ]: 13992149 : if(length > max_inline_length_){
67 : 19871 : inlined.len = (unsigned char)-1;
68 : 19871 : allocated.len = length;
69 : : }else{
70 : 13972278 : inlined.len = length;
71 : : }
72 : 13992149 : }
73 : :
74 : : void truncate(int newlen)
75 : : {
76 : 872500 : resize(newlen);
77 : 546015 : }
78 : :
79 : 2669329 : void assign(const char * newstr)
80 : : {
81 [ + + ]: 2669329 : if (!newstr) newstr = "";
82 : 2669329 : assign(newstr, strlen(newstr));
83 : 2669329 : }
84 : :
85 : 2941926 : void assign(const string &newstr)
86 : : {
87 : 2941926 : assign(newstr, newstr.length());
88 : 2941926 : }
89 : :
90 : 7831248 : void assign(const char * newstr, int end)
91 : : {
92 : 7831248 : resize(end);
93 : : copy(newstr, length(), raw());
94 : 7831248 : }
95 : :
96 : :
97 : : string& operator=(const char * newstr)
98 : : {
99 : 549504 : assign(newstr);
100 : 546232 : return *this;
101 : : }
102 : :
103 : : string& operator=(const string &newstr)
104 : : {
105 : 1318774 : assign(newstr);
106 : 5464 : return *this;
107 : : }
108 : :
109 : 436822 : string& operator+=(const string& other)
110 : : {
111 : : int current_end = length();
112 : 436822 : resize(length() + other.length());
113 : 436822 : copy(other.data(), other.length(), raw() + current_end);
114 : 436822 : return *this;
115 : : }
116 : :
117 : 21755 : string& operator+=(const char *other)
118 : : {
119 : : int current_end = length();
120 : 21755 : int otherlen=(int)strlen(other);
121 : 21755 : resize(length() + otherlen);
122 : 21755 : copy(other, otherlen, raw() + current_end);
123 : 21755 : return *this;
124 : : }
125 : :
126 : 4829363 : string& operator+=(char c)
127 : : {
128 : 4829363 : resize(length() + 1);
129 : 4829363 : raw()[length() - 1] = c;
130 : 4829363 : return *this;
131 : : }
132 : :
133 : : string operator+(char right) const
134 : : {
135 : : string ret=*this;
136 : : ret+=right;
137 : : return ret;
138 : : }
139 : :
140 : : string operator+(const char * right) const
141 : : {
142 : 20672 : string ret=*this;
143 : 20672 : ret+=right;
144 : 69 : return ret;
145 : : }
146 : :
147 : 2605 : bool operator==(const char * right) const
148 : : {
149 : 2605 : return !strcmp(data(), right);
150 : : }
151 : :
152 : 52 : bool operator==(const string& right) const
153 : : {
154 : 52 : return !strcmp(data(), right.data());
155 : : }
156 : :
157 : 817 : bool operator!=(const char * right) const
158 : : {
159 : 817 : 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 : : operator const char*() const
168 : : {
169 : : return data();
170 : : }
171 : :
172 : 214521 : explicit operator bool() const
173 : : {
174 : 214521 : return length();
175 : : }
176 : :
177 : 8227982 : string()
178 : 8227982 : {
179 : : //todo reduce I know this isn't all needed
180 : 8227982 : allocated.bufferlen = 0;
181 : 8227982 : allocated.str = 0;
182 : 8227982 : allocated.len = 0;
183 : 8227982 : inlined.len = 0;
184 : 8227982 : cached_data = inlined.str;
185 : 8227982 : next_resize = max_inline_length_+1;
186 : :
187 : 8227982 : }
188 : 1885859 : string(const char * newstr) : string()
189 : : {
190 : 1885859 : assign(newstr);
191 : 1885859 : }
192 : 1305810 : string(const char * newstr, int newlen) : string()
193 : : {
194 : 1305810 : assign(newstr, newlen);
195 : 1305810 : }
196 : 233966 : string(const string& old) : string()
197 : : {
198 : 233966 : assign(old.data());
199 : 233966 : }
200 : :
201 : 537 : string(string &&move) : string()
202 : : {
203 : : *this = move;
204 : 537 : }
205 : :
206 : 1411975 : string& operator=(string&& move)
207 : : {
208 : 350 : if(!is_inlined()) free(allocated.str);
209 : 1411975 : if(!move.is_inlined()){
210 : 461 : allocated.str = move.allocated.str;
211 : 461 : allocated.bufferlen = move.allocated.bufferlen;
212 : 461 : set_length(move.allocated.len);
213 : :
214 : 461 : move.inlined.len = 0;
215 : 461 : move.inlined.str[0] = 0;
216 : 461 : cached_data = allocated.str;
217 : 461 : next_resize = move.next_resize;
218 : :
219 : : }else{
220 : 1411514 : inlined.len = 0;
221 : 1411514 : cached_data = inlined.str;
222 : 1411514 : next_resize = max_inline_length_+1;
223 : 1411514 : assign(move);
224 : : }
225 : 1411975 : return *this;
226 : : }
227 : :
228 : 8227971 : ~string()
229 : : {
230 : 8227971 : if(!is_inlined()){
231 : 3840 : free(allocated.str);
232 : : }
233 : 8227971 : }
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 : 13991688 : void resize(int new_length)
269 : : {
270 : : const char *old_data = data();
271 [ + + + + ]: 14006591 : if(new_length >= next_resize || (!is_inlined() && new_length <= max_inline_length_)) {
272 [ + + - + ]: 4936 : if(new_length > max_inline_length_ && (is_inlined() || allocated.bufferlen <= new_length)){ //SSO or big to big
273 : 4563 : int new_size = bit_round(new_length + 1);
274 [ + + ]: 4563 : if(old_data == inlined.str){
275 : 8492 : allocated.str = copy(old_data, min_val(length(), new_length), (char *)malloc(new_size));
276 : : }else{
277 : 317 : allocated.str = (char *)realloc(allocated.str, new_size);
278 : : old_data = inlined.str; //this will prevent freeing a dead realloc ptr
279 : : }
280 : 4563 : allocated.bufferlen = new_size;
281 : 4563 : cached_data = allocated.str;
282 : 4563 : next_resize = allocated.bufferlen;
283 [ - + - + ]: 56 : }else if(length() > max_inline_length_ && new_length <= max_inline_length_){ //big to SSO
284 : 56 : copy(old_data, new_length, inlined.str);
285 : 56 : cached_data = inlined.str;
286 : 56 : next_resize = max_inline_length_+1;
287 : : }
288 [ + + + - ]: 4619 : if(old_data != inlined.str && old_data != data()){
289 : 56 : free((char *)old_data);
290 : : }
291 : : }
292 : 13991688 : set_length(new_length);
293 : :
294 : 13991688 : raw()[new_length] = 0; //always ensure null terminator
295 : 13991688 : }
296 : :
297 : : bool is_inlined() const
298 : : {
299 [ + + + + : 48815968 : 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 : 563 : inline char ** split(char * str, const char * key, int * len= nullptr) { return nsplit(str, key, 0, len); }
311 : 873228 : inline char ** qsplit(char * str, const char * key, int * len= nullptr) { return qnsplit(str, key, 0, len); }
312 : 110033 : 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 : 0 : inline string hex(unsigned int value)
324 : : {
325 : : char buffer[64];
326 : : if(0);
327 [ # # ]: 0 : else if (value<=0x000000FF) sprintf(buffer, "%.2X", value);
328 [ # # ]: 0 : else if (value<=0x0000FFFF) sprintf(buffer, "%.4X", value);
329 [ # # ]: 0 : else if (value<=0x00FFFFFF) sprintf(buffer, "%.6X", value);
330 : 0 : else sprintf(buffer, "%.8X", value);
331 : 0 : 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 : 0 : inline string hex2(unsigned int value)
349 : : {
350 : : char buffer[64];
351 : 0 : sprintf(buffer, "%.2X", value);
352 : 0 : 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 : 0 : inline string hex4(unsigned int value)
363 : : {
364 : : char buffer[64];
365 : 0 : sprintf(buffer, "%.4X", value);
366 : 0 : 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 : 1 : inline string hex6(unsigned int value)
377 : : {
378 : : char buffer[64];
379 : 1 : sprintf(buffer, "%.6X", value);
380 : 1 : return buffer;
381 : : }
382 : :
383 : 0 : inline string hex8(unsigned int value)
384 : : {
385 : : char buffer[64];
386 : 0 : sprintf(buffer, "%.8X", value);
387 : 0 : return buffer;
388 : : }
389 : :
390 : 805 : inline string dec(int value)
391 : : {
392 : : char buffer[64];
393 : 805 : sprintf(buffer, "%i", value);
394 : 805 : return buffer;
395 : : }
396 : :
397 : 105603 : 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 : : 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 : 105603 : sprintf(rval, "%.100f", value);
405 [ + - ]: 105603 : if (strchr(rval, '.'))//nuke useless zeroes
406 : : {
407 : 105603 : char * end=strrchr(rval, '\0')-1;
408 [ + + ]: 10665729 : while (*end=='0')
409 : : {
410 : 10560126 : *end='\0';
411 : 10560126 : end--;
412 : : }
413 [ + + ]: 105603 : if (*end=='.') *end='\0';
414 : : }
415 : 105603 : return rval;
416 : : }
417 : :
418 : : // Same as above, but with variable precision
419 : 23 : inline string ftostrvar(double value, int precision)
420 : : {
421 : : int clampedprecision = precision;
422 : : if (clampedprecision < 0) clampedprecision = 0;
423 : 23 : if (clampedprecision > 100) clampedprecision = 100;
424 : :
425 : : // see above
426 : : char rval[512];
427 : 23 : sprintf(rval, "%.*f", clampedprecision, (double)value);
428 [ + + ]: 23 : if (strchr(rval, '.'))//nuke useless zeroes
429 : : {
430 : 22 : char * end = strrchr(rval, '\0') - 1;
431 [ + + ]: 91 : while (*end == '0')
432 : : {
433 : 69 : *end = '\0';
434 : 69 : end--;
435 : : }
436 [ + + ]: 22 : if (*end == '.') *end = '\0';
437 : : }
438 : 23 : return rval;
439 : : }
440 : :
441 : 1398871 : inline bool stribegin(const char * str, const char * key)
442 : : {
443 [ + + ]: 2139278 : for (int i=0;key[i];i++)
444 : : {
445 [ + + ]: 2029628 : if (to_lower(str[i])!=to_lower(key[i])) return false;
446 : : }
447 : : return true;
448 : : }
449 : :
450 : 3930 : inline bool striend(const char * str, const char * key)
451 : : {
452 : : const char * keyend=strrchr(key, '\0');
453 : : const char * strend=strrchr(str, '\0');
454 [ + + ]: 5091 : while (key!=keyend)
455 : : {
456 : 4374 : keyend--;
457 : 4374 : strend--;
458 [ + + ]: 4374 : if (to_lower(*strend)!=to_lower(*keyend)) return false;
459 : : }
460 : : return true;
461 : : }
462 : :
463 : 56635 : inline bool stricmpwithupper(const char *word1, const char *word2)
464 : : {
465 [ + + ]: 65085 : while(*word2)
466 : : {
467 [ + + ]: 63247 : if(to_upper(*word1++) != *word2++) return true;
468 : : }
469 : 1838 : return *word1;
470 : : }
471 : :
472 : 5234383 : inline bool stricmpwithlower(const char *word1, const char *word2)
473 : : {
474 [ + + ]: 10343011 : while(*word2)
475 : : {
476 [ + + ]: 9491453 : if(to_lower(*word1++) != *word2++) return true;
477 : : }
478 : 851558 : 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 : 754 : inline const char * dequote(char * str)
487 : : {
488 [ + + ]: 754 : if (*str!='"') return str;
489 : : int inpos=1;
490 : : int outpos=0;
491 : : while (true)
492 : : {
493 [ + + ]: 9193 : if (str[inpos]=='"')
494 : : {
495 [ + + ]: 784 : if (str[inpos+1]=='"') inpos++;
496 [ + - ]: 712 : else if (str[inpos+1]=='\0') break;
497 : : else return nullptr;
498 : : }
499 [ + - ]: 8481 : if (!str[inpos]) return nullptr;
500 : 8481 : str[outpos++]=str[inpos++];
501 : : }
502 : 712 : str[outpos]=0;
503 : 712 : return str;
504 : : }
505 : :
506 : 11145 : inline char * strqchr(const char * str, char key)
507 : : {
508 [ + + ]: 94677 : while (*str != '\0')
509 : : {
510 [ + + ]: 85652 : if (*str == key) { return const_cast<char*>(str); }
511 [ + + + + ]: 83534 : 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 [ + + + + : 480 : if (str[0] == '\'' && str[1] == '\'' && str[2] == '\'') { str += 2; }
+ - ]
516 : : else
517 : : {
518 : : char delimiter = *str;
519 : :
520 : : do
521 : : {
522 : 6561 : str++;
523 : :
524 : : // If we want to support backslash escapes, we'll have to add that right here.
525 [ + + + + ]: 6561 : } 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 [ + + ]: 476 : if (*str == '\0') { return nullptr; }
529 : : }
530 : : }
531 : :
532 : 83532 : str++;
533 : : }
534 : :
535 : : return nullptr;
536 : : }
537 : :
538 : : // RPG Hacker: WOW, these functions are poopy!
539 : 5686 : inline char * strqrchr(const char * str, char key)
540 : : {
541 : : const char * ret= nullptr;
542 [ + + ]: 41522 : while (*str)
543 : : {
544 [ + + + + ]: 35836 : if (*str=='"' || *str=='\'')
545 : : {
546 : : char token = *str;
547 : :
548 : 335 : str++;
549 : :
550 : : // Special case hack for '''
551 [ + + + + ]: 335 : if (str[0] == '\'' && str[1] == '\'') { str += 2; }
552 : : else
553 : : {
554 [ + + ]: 3493 : while (*str != token)
555 : : {
556 [ + - ]: 3160 : if (!*str) return nullptr;
557 : 3160 : str++;
558 : : }
559 : 333 : str++;
560 : : }
561 : : }
562 : : else
563 : : {
564 [ + + ]: 35501 : if (*str==key) ret=str;
565 : 35501 : str++;
566 : : }
567 : : }
568 : : return const_cast<char*>(ret);
569 : : }
570 : :
571 : : inline string substr(const char * str, int len)
572 : : {
573 : 1320 : 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 : 0 : inline string &lower(string &old)
592 : : {
593 : : int length = old.length();
594 [ # # ]: 0 : for (int i=0;i<length;i++) old.raw()[i]=(char)to_lower(old.data()[i]);
595 : 0 : 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 : 436216 : inline int getconnectedlines(stringarraytype& lines, int startline, string& out)
625 : : {
626 : 436216 : out = string("");
627 : : int count = 1;
628 : :
629 [ + - ]: 436744 : for (int i = startline; lines[i]; i++)
630 : : {
631 : : // The line should already be stripped of any comments at this point
632 : 436225 : int linestartpos = (int)strlen(lines[i]);
633 : :
634 : : bool found = false;
635 : :
636 [ + + ]: 867558 : for (int j = linestartpos; j > 0; j--)
637 : : {
638 [ + - + + : 864133 : if (!is_space(lines[i][j]) && lines[i][j] != '\0' && lines[i][j] != ';')
+ - ]
639 : : {
640 [ + + ]: 431243 : if (lines[i][j] == '\\')
641 : : {
642 : 9 : count++;
643 : 9 : out += string(lines[i], j);
644 : : found = true;
645 : 9 : break;
646 : : }
647 : : else
648 : : {
649 : 431234 : out += string(lines[i], j + 1);
650 : 431234 : return count - 1;
651 : : }
652 : : }
653 : : }
654 : :
655 [ + + ]: 4991 : if (!found)
656 : : {
657 : 4982 : out += string(lines[i], 1);
658 : 4982 : return count - 1;
659 : : }
660 : : }
661 : :
662 : 0 : return count - 1;
663 : : }
|