asar coverage - build #264


src/asar/
File: src/asar/libstr.h
Date: 2025-02-28 06:49:25
Lines:
200/215
93.0%
Functions:
54/57
94.7%
Branches:
110/164
67.1%

Line Branch Exec Source
1 #pragma once
2
3 #include "std-includes.h"
4 #include "libmisc.h"
5 #include <cstdint>
6 #include <cstring>
7 #include <utility>
8 #include <string_view>
9
10 //ty alcaro
11 extern const unsigned char char_props[256];
12 1655422 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 243666 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 49610 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 14553 inline bool is_ualpha(unsigned char c) { return char_props[c] & 0x28; }
23 124735 inline bool is_ualnum(unsigned char c) { return char_props[c] & 0x68; }
24 7981 inline bool is_xdigit(unsigned char c) { return char_props[c] & 0x01; }
25
26 1294925 inline char *copy(const char *source, int copy_length, char *dest)
27 {
28
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 597756 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 597756 times.
1294925 memcpy(dest, source, copy_length*sizeof(char));
29 1294925 return dest;
30 }
31
32 class string {
33 public:
34 3019537 const char *data() const
35 {
36 3019537 return data_ptr;
37 }
38
39 120860 char *temp_raw() const //things to cleanup and take a look at
40 {
41 120860 return data_ptr;
42 }
43
44 442732 char *raw() const
45 {
46 442732 return data_ptr;
47 }
48
49 3214121 int length() const
50 {
51 3214121 return len;
52 }
53
54 1882059 void resize(unsigned int new_length)
55 {
56
2/2
✓ Branch 0 taken 4559 times.
✓ Branch 1 taken 1877500 times.
1882059 if (new_length > capacity()) {
57 4559 reallocate_capacity(new_length);
58 }
59
60 1882059 len = new_length;
61 1882059 data_ptr[new_length] = 0; //always ensure null terminator
62 1882059 }
63
64 792 void truncate(int newlen)
65 {
66 792 resize(newlen);
67 792 }
68
69 662849 void assign(const char * newstr)
70 {
71
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 662846 times.
662849 if (!newstr) newstr = "";
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313077 times.
662849 assign(newstr, strlen(newstr));
73 662849 }
74
75 356630 void assign(const string &newstr)
76 {
77 356630 assign(newstr.data(), newstr.length());
78 356630 }
79
80 1098910 void assign(const char * newstr, int end)
81 {
82 1098910 resize(end);
83 1098910 copy(newstr, end, data_ptr);
84 1098910 }
85
86
87 237451 string& operator=(const char * newstr)
88 {
89 237451 assign(newstr);
90 237451 return *this;
91 }
92
93 356630 string& operator=(const string &newstr)
94 {
95 356630 assign(newstr);
96 356630 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 3384 string& append(const char *other, int start, int end)
108 {
109 3384 int current_end = length();
110 3384 resize(length() + end - start);
111 3384 copy(other + start, end - start, data_ptr + current_end);
112 3384 return *this;
113 }
114
115 52401 string& operator+=(const string& other)
116 {
117 52401 int current_end = length();
118 52401 resize(length() + other.length());
119 52401 copy(other.data(), other.length(), data_ptr + current_end);
120 52401 return *this;
121 }
122
123 135851 string& operator+=(const char *other)
124 {
125 135851 int current_end = length();
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62643 times.
135851 int otherlen=(int)strlen(other);
127 135851 resize(length() + otherlen);
128 135851 copy(other, otherlen, data_ptr + current_end);
129 135851 return *this;
130 }
131
132 590717 string& operator+=(char c)
133 {
134 590717 resize(length() + 1);
135 590717 data_ptr[length() - 1] = c;
136 590717 return *this;
137 }
138
139 string operator+(char right) const
140 {
141 string ret=*this;
142 ret+=right;
143 return ret;
144 }
145
146 24725 string operator+(const char * right) const
147 {
148 24725 string ret=*this;
149
1/2
✓ Branch 0 taken 24725 times.
✗ Branch 1 not taken.
24725 ret+=right;
150 24725 return ret;
151 }
152
153 2108626 operator const char*() const
154 {
155 2108626 return data();
156 }
157
158 10658 explicit operator bool() const
159 {
160 10658 return length();
161 }
162
163 1387694 string()
164 1387694 {
165 1387694 data_ptr = inlined.data;
166 1387694 len = 0;
167 1387694 inlined.data[0] = '\0';
168 1387694 }
169 330966 string(const char * newstr) : string()
170 {
171
1/2
✓ Branch 0 taken 330966 times.
✗ Branch 1 not taken.
330966 assign(newstr);
172 330966 }
173 67212 string(const char * newstr, int newlen) : string()
174 {
175
1/2
✓ Branch 0 taken 67212 times.
✗ Branch 1 not taken.
67212 assign(newstr, newlen);
176 67212 }
177 94432 string(const string& old) : string()
178 {
179
1/2
✓ Branch 0 taken 94432 times.
✗ Branch 1 not taken.
94432 assign(old.data());
180 94432 }
181
182 14177 string(string &&move) noexcept : string()
183 {
184 14177 *this = move;
185 14177 }
186
187 71508 string& operator=(string&& other) noexcept
188 {
189
2/2
✓ Branch 0 taken 71470 times.
✓ Branch 1 taken 38 times.
71508 if (other.is_inlined()) {
190 // No resources to steal so just do a normal assignment
191 71470 *this = other;
192 } else {
193
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (is_inlined()) {
194 38 data_ptr = other.data_ptr;
195 38 other.data_ptr = 0;
196 } else {
197 // Give our old allocation back so other can free it for us
198 std::swap(data_ptr, other.data_ptr);
199 }
200 38 len = other.len;
201 38 allocated = other.allocated;
202 }
203 71508 return *this;
204 }
205
206 1344597 ~string()
207 {
208
2/2
✓ Branch 0 taken 4417 times.
✓ Branch 1 taken 1340180 times.
1344597 if(!is_inlined()){
209 4417 free(data_ptr);
210 }
211 1344597 }
212
213 //maybe these should return refs to chain. but also good not to encourage chaining
214 11 void strip_prefix(char c)
215 {
216
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
11 if(data()[0] == c){
217
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 std::memmove(data_ptr, data_ptr + 1, length() - 1);
218 4 resize(length() - 1);
219 }
220 11 }
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 #ifdef SERIALIZER
247 void serialize(serializer & s)
248 {
249 s(str, allocated.bufferlen);
250 resize(strlen(str));
251 }
252 #endif
253 #define SERIALIZER_BANNED
254
255 private:
256 static const int scale_factor = 4; //scale sso
257 static const int inline_capacity = ((sizeof(char *) + sizeof(int) * 2) * scale_factor) - 2;
258
259 // Points to a malloc'd data block or to inlined.data
260 char *data_ptr;
261 unsigned int len;
262 union {
263 struct {
264 // Actual allocated capacity is +1 this value, to cover for the terminating NUL
265 unsigned int capacity;
266 } allocated;
267 struct {
268 char data[inline_capacity + 1];
269 } inlined;
270 };
271
272 void reallocate_capacity(unsigned int new_length);
273
274 1882059 unsigned capacity() const
275 {
276
2/2
✓ Branch 0 taken 1880477 times.
✓ Branch 1 taken 1582 times.
1882059 return is_inlined() ? inline_capacity : allocated.capacity;
277 }
278
279 3302761 bool is_inlined() const
280 {
281 3302761 return data_ptr == inlined.data;
282 }
283 };
284 #define STR (string)
285
286 #define ASAR_STRCMP_OPERATORS(op) \
287 inline bool operator op(const string& left, const string& right) { \
288 return strcmp(left, right) op 0; \
289 } \
290 inline bool operator op(const string& left, const char* right) { \
291 return strcmp(left, right) op 0; \
292 } \
293 inline bool operator op(const char* left, const string& right) { \
294 return strcmp(left, right) op 0; \
295 }
296
297
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 3642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24587 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20945 times.
58821 ASAR_STRCMP_OPERATORS(==)
298
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2026 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2026 times.
5692 ASAR_STRCMP_OPERATORS(!=)
299 ASAR_STRCMP_OPERATORS(<)
300 ASAR_STRCMP_OPERATORS(<=)
301 ASAR_STRCMP_OPERATORS(>)
302 ASAR_STRCMP_OPERATORS(>=)
303 #undef ASAR_STRCMP_OPERATORS
304
305 template<>
306 struct std::hash<string> {
307 71871 size_t operator()(const ::string& s) const {
308 71871 return std::hash<std::string_view>()(std::string_view(s.data(), s.length()));
309 }
310 };
311
312 char * readfile(const char * fname, const char * basepath);
313 char * readfilenative(const char * fname);
314 bool readfile(const char * fname, const char * basepath, char ** data, int * len);//if you want an uchar*, cast it
315 char ** split(char * str, char key, int * len= nullptr);
316 char ** qsplit(char * str, char key, int * len= nullptr);
317 char ** qpsplit(char * str, char key, int * len= nullptr);
318 char ** qsplitstr(char * str, const char * key, int * len= nullptr);
319 bool confirmquotes(const char * str);
320 bool confirmqpar(const char * str);
321 char* strqpchr(char* str, char key);
322 char* strqpstr(char* str, const char* key);
323
324 inline string hex(unsigned int value)
325 {
326 char buffer[64];
327 if(0);
328 else if (value<=0x000000FF) snprintf(buffer, sizeof(buffer), "%.2X", value);
329 else if (value<=0x0000FFFF) snprintf(buffer, sizeof(buffer), "%.4X", value);
330 else if (value<=0x00FFFFFF) snprintf(buffer, sizeof(buffer), "%.6X", value);
331 else snprintf(buffer, sizeof(buffer), "%.8X", value);
332 return buffer;
333 }
334
335 2 inline string hex(unsigned int value, int width)
336 {
337 1 char buffer[64];
338
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 snprintf(buffer, sizeof(buffer), "%.*X", width, value);
339
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 return buffer;
340 }
341
342 1376 inline string dec(int value)
343 {
344 745 char buffer[64];
345
2/2
✓ Branch 0 taken 631 times.
✓ Branch 1 taken 745 times.
1376 snprintf(buffer, sizeof(buffer), "%i", value);
346
1/2
✓ Branch 0 taken 1376 times.
✗ Branch 1 not taken.
2752 return buffer;
347 }
348
349 2166 inline string ftostr(double value)
350 {
351 // randomdude999: With 100 digits of precision, the buffer needs to be approx. 311+100,
352 // but let's be safe here https://stackoverflow.com/questions/7235456
353 1083 char rval[512];
354 // RPG Hacker: Ridiculously high precision, I know, but we're working with doubles
355 // here and can afford it, so no need to waste any precision
356
1/2
✓ Branch 0 taken 1083 times.
✗ Branch 1 not taken.
2166 snprintf(rval, sizeof(rval), "%.100f", value);
357
1/2
✓ Branch 0 taken 2166 times.
✗ Branch 1 not taken.
2166 if (strchr(rval, '.'))//nuke useless zeroes
358 {
359 2166 char * end=strrchr(rval, '\0')-1;
360
2/2
✓ Branch 0 taken 216252 times.
✓ Branch 1 taken 2166 times.
218418 while (*end=='0')
361 {
362 216252 *end='\0';
363 216252 end--;
364 }
365
2/2
✓ Branch 0 taken 2160 times.
✓ Branch 1 taken 6 times.
2166 if (*end=='.') *end='\0';
366 }
367
1/2
✓ Branch 0 taken 2166 times.
✗ Branch 1 not taken.
4332 return rval;
368 }
369
370 // Same as above, but with variable precision
371 24 inline string ftostrvar(double value, int precision)
372 {
373 24 int clampedprecision = precision;
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (clampedprecision < 0) clampedprecision = 0;
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (clampedprecision > 100) clampedprecision = 100;
376
377 // see above
378 12 char rval[512];
379
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 snprintf(rval, sizeof(rval), "%.*f", clampedprecision, (double)value);
380
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
24 if (strchr(rval, '.'))//nuke useless zeroes
381 {
382 22 char * end = strrchr(rval, '\0') - 1;
383
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 22 times.
68 while (*end == '0')
384 {
385 46 *end = '\0';
386 46 end--;
387 }
388
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 if (*end == '.') *end = '\0';
389 }
390
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
48 return rval;
391 }
392
393 83349 inline bool stribegin(const char * str, const char * key)
394 {
395
2/2
✓ Branch 0 taken 227306 times.
✓ Branch 1 taken 7016 times.
234322 for (int i=0;key[i];i++)
396 {
397
2/2
✓ Branch 0 taken 76333 times.
✓ Branch 1 taken 150973 times.
227306 if (to_lower(str[i])!=to_lower(key[i])) return false;
398 }
399 7016 return true;
400 }
401
402 inline bool striend(const char * str, const char * key)
403 {
404 const char * keyend=strrchr(key, '\0');
405 const char * strend=strrchr(str, '\0');
406 if(keyend-key > strend-str) return false;
407
408 while (key!=keyend)
409 {
410 keyend--;
411 strend--;
412 if (to_lower(*strend)!=to_lower(*keyend)) return false;
413 }
414 return true;
415 }
416
417 inline bool stricmpwithupper(const char *word1, const char *word2)
418 {
419 while(*word2)
420 {
421 if(to_upper(*word1++) != *word2++) return true;
422 }
423 return *word1;
424 }
425
426 622856 inline bool stricmpwithlower(const char *word1, const char *word2)
427 {
428
2/2
✓ Branch 0 taken 841390 times.
✓ Branch 1 taken 35840 times.
877230 while(*word2)
429 {
430
2/2
✓ Branch 0 taken 587016 times.
✓ Branch 1 taken 254374 times.
841390 if(to_lower(*word1++) != *word2++) return true;
431 }
432 35840 return *word1;
433 }
434
435 //function: return the string without quotes around it, if any exists
436 //if they don't exist, return it unaltered
437 //it is not guaranteed to return str
438 //it is not guaranteed to not edit str
439 //the input must be freed even though it's garbage, the output must not
440 6515 inline const char * dequote(char * str)
441 {
442
2/2
✓ Branch 0 taken 780 times.
✓ Branch 1 taken 5735 times.
6515 if (*str!='"') return str;
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2035 times.
5735 char *end = strrchr(str, '"');
444
1/2
✓ Branch 0 taken 5735 times.
✗ Branch 1 not taken.
5735 if (end)
445 {
446 5735 *end = 0;
447 5735 char *quote = str+1;
448
7/10
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3772 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 72 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 72 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2107 times.
✓ Branch 8 taken 72 times.
✓ Branch 9 taken 2035 times.
5879 while((quote = strstr(quote, "\"\""))) memmove(quote, quote+1, strlen(quote));
449 5735 return str + 1;
450 }
451 return nullptr;
452 }
453
454 15559 inline char * strqchr(const char * str, char key)
455 {
456
2/2
✓ Branch 0 taken 138348 times.
✓ Branch 1 taken 11765 times.
150113 while (*str != '\0')
457 {
458
2/2
✓ Branch 0 taken 3792 times.
✓ Branch 1 taken 134556 times.
138348 if (*str == key) { return const_cast<char*>(str); }
459
4/4
✓ Branch 0 taken 133905 times.
✓ Branch 1 taken 651 times.
✓ Branch 2 taken 184 times.
✓ Branch 3 taken 133721 times.
134556 else if (*str == '"' || *str == '\'')
460 {
461 // Special case hack for ''', which is currently our official way of handling the ' character.
462 // Even though it really stinks.
463
5/6
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 651 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 172 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
835 if (str[0] == '\'' && str[1] == '\'' && str[2] == '\'') { str += 2; }
464 else
465 {
466 823 char delimiter = *str;
467
468 do
469 {
470 8947 str++;
471
472 // If we want to support backslash escapes, we'll have to add that right here.
473
4/4
✓ Branch 0 taken 8126 times.
✓ Branch 1 taken 821 times.
✓ Branch 2 taken 8124 times.
✓ Branch 3 taken 2 times.
8947 } while (*str != delimiter && *str != '\0');
474
475 // This feels like a superfluous check, but I can't really find a clean way to avoid it.
476
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 821 times.
823 if (*str == '\0') { return nullptr; }
477 }
478 }
479
480 134554 str++;
481 }
482
483 11765 return nullptr;
484 }
485
486 2580 inline string substr(const char * str, int len)
487 {
488 2580 return string(str, len);
489 }
490
491
492 64902 inline char *strip_whitespace(char *str)
493 {
494
2/2
✓ Branch 0 taken 3499 times.
✓ Branch 1 taken 64902 times.
68401 while(is_space(*str)) str++;
495
4/4
✓ Branch 0 taken 30165 times.
✓ Branch 1 taken 42305 times.
✓ Branch 2 taken 28911 times.
✓ Branch 3 taken 10527 times.
80046 for(int i = strlen(str) - 1; i >= 0; i--)
496 {
497
2/2
✓ Branch 0 taken 43932 times.
✓ Branch 1 taken 15144 times.
59076 if(!is_space(str[i]))
498 {
499 43932 str[i + 1] = 0;
500 43932 return str;
501 }
502 }
503 20970 return str;
504 }
505 267 inline void strip_whitespace(string &str)
506 {
507
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 str = string(strip_whitespace(str.temp_raw()));
508 267 }
509
510 string &itrim(string &str, const char * left, const char * right);
511
512 7743 inline string &lower(string &old)
513 {
514 7743 int length = old.length();
515
2/2
✓ Branch 0 taken 223781 times.
✓ Branch 1 taken 7743 times.
231524 for (int i=0;i<length;i++) old.raw()[i]=(char)to_lower(old.data()[i]);
516 7743 return old;
517 }
518
519
520 // Returns number of connected lines - 1
521 template<typename stringarraytype>
522 46405 inline int getconnectedlines(stringarraytype& lines, int startline, string& out)
523 {
524 46405 int count = 0;
525
526
1/2
✓ Branch 0 taken 46423 times.
✗ Branch 1 not taken.
46423 for (int i = startline; lines[i]; i++)
527 {
528 // The line should already be stripped of any comments at this point
529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22526 times.
46423 int linestartpos = (int)strlen(lines[i]);
530
531
4/4
✓ Branch 0 taken 33017 times.
✓ Branch 1 taken 13406 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 32999 times.
46423 if(linestartpos && lines[i][linestartpos - 1] == '\\')
532 {
533 18 count++;
534
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 out += string(lines[i], linestartpos - 1);
535 18 continue;
536 }
537 else
538 {
539
2/4
✓ Branch 0 taken 46405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46405 times.
✗ Branch 3 not taken.
46405 out += string(lines[i], linestartpos);
540 46405 return count;
541 }
542 }
543
544 return count;
545 }
546