1 /*
2 * Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <wchar.h>
24 #include <wctype.h>
25 #include <limits.h>
26
27 #include "c99defs.h"
28 #include "dstr.h"
29 #include "darray.h"
30 #include "bmem.h"
31 #include "utf8.h"
32 #include "lexer.h"
33 #include "platform.h"
34
35 static const char *astrblank = "";
36 static const wchar_t *wstrblank = L"";
37
astrcmpi(const char * str1,const char * str2)38 int astrcmpi(const char *str1, const char *str2)
39 {
40 if (!str1)
41 str1 = astrblank;
42 if (!str2)
43 str2 = astrblank;
44
45 do {
46 char ch1 = (char)toupper(*str1);
47 char ch2 = (char)toupper(*str2);
48
49 if (ch1 < ch2)
50 return -1;
51 else if (ch1 > ch2)
52 return 1;
53 } while (*str1++ && *str2++);
54
55 return 0;
56 }
57
wstrcmpi(const wchar_t * str1,const wchar_t * str2)58 int wstrcmpi(const wchar_t *str1, const wchar_t *str2)
59 {
60 if (!str1)
61 str1 = wstrblank;
62 if (!str2)
63 str2 = wstrblank;
64
65 do {
66 wchar_t ch1 = (wchar_t)towupper(*str1);
67 wchar_t ch2 = (wchar_t)towupper(*str2);
68
69 if (ch1 < ch2)
70 return -1;
71 else if (ch1 > ch2)
72 return 1;
73 } while (*str1++ && *str2++);
74
75 return 0;
76 }
77
astrcmp_n(const char * str1,const char * str2,size_t n)78 int astrcmp_n(const char *str1, const char *str2, size_t n)
79 {
80 if (!n)
81 return 0;
82 if (!str1)
83 str1 = astrblank;
84 if (!str2)
85 str2 = astrblank;
86
87 do {
88 char ch1 = *str1;
89 char ch2 = *str2;
90
91 if (ch1 < ch2)
92 return -1;
93 else if (ch1 > ch2)
94 return 1;
95 } while (*str1++ && *str2++ && --n);
96
97 return 0;
98 }
99
wstrcmp_n(const wchar_t * str1,const wchar_t * str2,size_t n)100 int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n)
101 {
102 if (!n)
103 return 0;
104 if (!str1)
105 str1 = wstrblank;
106 if (!str2)
107 str2 = wstrblank;
108
109 do {
110 wchar_t ch1 = *str1;
111 wchar_t ch2 = *str2;
112
113 if (ch1 < ch2)
114 return -1;
115 else if (ch1 > ch2)
116 return 1;
117 } while (*str1++ && *str2++ && --n);
118
119 return 0;
120 }
121
astrcmpi_n(const char * str1,const char * str2,size_t n)122 int astrcmpi_n(const char *str1, const char *str2, size_t n)
123 {
124 if (!n)
125 return 0;
126 if (!str1)
127 str1 = astrblank;
128 if (!str2)
129 str2 = astrblank;
130
131 do {
132 char ch1 = (char)toupper(*str1);
133 char ch2 = (char)toupper(*str2);
134
135 if (ch1 < ch2)
136 return -1;
137 else if (ch1 > ch2)
138 return 1;
139 } while (*str1++ && *str2++ && --n);
140
141 return 0;
142 }
143
wstrcmpi_n(const wchar_t * str1,const wchar_t * str2,size_t n)144 int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n)
145 {
146 if (!n)
147 return 0;
148 if (!str1)
149 str1 = wstrblank;
150 if (!str2)
151 str2 = wstrblank;
152
153 do {
154 wchar_t ch1 = (wchar_t)towupper(*str1);
155 wchar_t ch2 = (wchar_t)towupper(*str2);
156
157 if (ch1 < ch2)
158 return -1;
159 else if (ch1 > ch2)
160 return 1;
161 } while (*str1++ && *str2++ && --n);
162
163 return 0;
164 }
165
astrstri(const char * str,const char * find)166 char *astrstri(const char *str, const char *find)
167 {
168 size_t len;
169
170 if (!str || !find)
171 return NULL;
172
173 len = strlen(find);
174
175 do {
176 if (astrcmpi_n(str, find, len) == 0)
177 return (char *)str;
178 } while (*str++);
179
180 return NULL;
181 }
182
wstrstri(const wchar_t * str,const wchar_t * find)183 wchar_t *wstrstri(const wchar_t *str, const wchar_t *find)
184 {
185 size_t len;
186
187 if (!str || !find)
188 return NULL;
189
190 len = wcslen(find);
191
192 do {
193 if (wstrcmpi_n(str, find, len) == 0)
194 return (wchar_t *)str;
195 } while (*str++);
196
197 return NULL;
198 }
199
is_padding(int ch)200 static inline bool is_padding(int ch)
201 {
202 return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
203 }
204
strdepad(char * str)205 char *strdepad(char *str)
206 {
207 char *temp;
208 size_t len;
209
210 if (!str)
211 return str;
212 if (!*str)
213 return str;
214
215 temp = str;
216
217 /* remove preceding spaces/tabs */
218 while (is_padding(*temp))
219 ++temp;
220
221 len = strlen(temp);
222 if (temp != str)
223 memmove(str, temp, len + 1);
224
225 if (len) {
226 temp = str + (len - 1);
227 while (is_padding(*temp))
228 *(temp--) = 0;
229 }
230
231 return str;
232 }
233
wcsdepad(wchar_t * str)234 wchar_t *wcsdepad(wchar_t *str)
235 {
236 wchar_t *temp;
237 size_t len;
238
239 if (!str)
240 return str;
241 if (!*str)
242 return str;
243
244 temp = str;
245
246 /* remove preceding spaces/tabs */
247 while (is_padding(*temp))
248 ++temp;
249
250 len = wcslen(temp);
251 if (temp != str)
252 memmove(str, temp, (len + 1) * sizeof(wchar_t));
253
254 if (len) {
255 temp = str + (len - 1);
256 while (is_padding(*temp))
257 *(temp--) = 0;
258 }
259
260 return str;
261 }
262
strlist_split(const char * str,char split_ch,bool include_empty)263 char **strlist_split(const char *str, char split_ch, bool include_empty)
264 {
265 const char *cur_str = str;
266 const char *next_str;
267 char *out = NULL;
268 size_t count = 0;
269 size_t total_size = 0;
270
271 if (str) {
272 char **table;
273 char *offset;
274 size_t cur_idx = 0;
275 size_t cur_pos = 0;
276
277 next_str = strchr(str, split_ch);
278
279 while (next_str) {
280 size_t size = next_str - cur_str;
281
282 if (size || include_empty) {
283 ++count;
284 total_size += size + 1;
285 }
286
287 cur_str = next_str + 1;
288 next_str = strchr(cur_str, split_ch);
289 }
290
291 if (*cur_str || include_empty) {
292 ++count;
293 total_size += strlen(cur_str) + 1;
294 }
295
296 /* ------------------ */
297
298 cur_pos = (count + 1) * sizeof(char *);
299 total_size += cur_pos;
300 out = bmalloc(total_size);
301 offset = out + cur_pos;
302 table = (char **)out;
303
304 /* ------------------ */
305
306 next_str = strchr(str, split_ch);
307 cur_str = str;
308
309 while (next_str) {
310 size_t size = next_str - cur_str;
311
312 if (size || include_empty) {
313 table[cur_idx++] = offset;
314 strncpy(offset, cur_str, size);
315 offset[size] = 0;
316 offset += size + 1;
317 }
318
319 cur_str = next_str + 1;
320 next_str = strchr(cur_str, split_ch);
321 }
322
323 if (*cur_str || include_empty) {
324 table[cur_idx++] = offset;
325 strcpy(offset, cur_str);
326 }
327
328 table[cur_idx] = NULL;
329 }
330
331 return (char **)out;
332 }
333
strlist_free(char ** strlist)334 void strlist_free(char **strlist)
335 {
336 bfree(strlist);
337 }
338
dstr_init_copy_strref(struct dstr * dst,const struct strref * src)339 void dstr_init_copy_strref(struct dstr *dst, const struct strref *src)
340 {
341 dstr_init(dst);
342 dstr_copy_strref(dst, src);
343 }
344
dstr_copy(struct dstr * dst,const char * array)345 void dstr_copy(struct dstr *dst, const char *array)
346 {
347 size_t len;
348
349 if (!array || !*array) {
350 dstr_free(dst);
351 return;
352 }
353
354 len = strlen(array);
355 dstr_ensure_capacity(dst, len + 1);
356 memcpy(dst->array, array, len + 1);
357 dst->len = len;
358 }
359
dstr_copy_strref(struct dstr * dst,const struct strref * src)360 void dstr_copy_strref(struct dstr *dst, const struct strref *src)
361 {
362 if (dst->array)
363 dstr_free(dst);
364
365 dstr_ncopy(dst, src->array, src->len);
366 }
367
size_min(size_t a,size_t b)368 static inline size_t size_min(size_t a, size_t b)
369 {
370 return (a < b) ? a : b;
371 }
372
dstr_ncopy(struct dstr * dst,const char * array,const size_t len)373 void dstr_ncopy(struct dstr *dst, const char *array, const size_t len)
374 {
375 if (dst->array)
376 dstr_free(dst);
377
378 if (!len)
379 return;
380
381 dst->array = bmemdup(array, len + 1);
382 dst->len = len;
383 dst->capacity = len + 1;
384
385 dst->array[len] = 0;
386 }
387
dstr_ncopy_dstr(struct dstr * dst,const struct dstr * str,const size_t len)388 void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
389 {
390 size_t newlen;
391
392 if (dst->array)
393 dstr_free(dst);
394
395 if (!len)
396 return;
397
398 newlen = size_min(len, str->len);
399 dst->array = bmemdup(str->array, newlen + 1);
400 dst->len = newlen;
401 dst->capacity = newlen + 1;
402
403 dst->array[newlen] = 0;
404 }
405
dstr_cat_dstr(struct dstr * dst,const struct dstr * str)406 void dstr_cat_dstr(struct dstr *dst, const struct dstr *str)
407 {
408 size_t new_len;
409 if (!str->len)
410 return;
411
412 new_len = dst->len + str->len;
413
414 dstr_ensure_capacity(dst, new_len + 1);
415 memcpy(dst->array + dst->len, str->array, str->len + 1);
416 dst->len = new_len;
417 }
418
dstr_cat_strref(struct dstr * dst,const struct strref * str)419 void dstr_cat_strref(struct dstr *dst, const struct strref *str)
420 {
421 dstr_ncat(dst, str->array, str->len);
422 }
423
dstr_ncat(struct dstr * dst,const char * array,const size_t len)424 void dstr_ncat(struct dstr *dst, const char *array, const size_t len)
425 {
426 size_t new_len;
427 if (!array || !*array || !len)
428 return;
429
430 new_len = dst->len + len;
431
432 dstr_ensure_capacity(dst, new_len + 1);
433 memcpy(dst->array + dst->len, array, len);
434
435 dst->len = new_len;
436 dst->array[new_len] = 0;
437 }
438
dstr_ncat_dstr(struct dstr * dst,const struct dstr * str,const size_t len)439 void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
440 {
441 size_t new_len, in_len;
442 if (!str->array || !*str->array || !len)
443 return;
444
445 in_len = size_min(len, str->len);
446 new_len = dst->len + in_len;
447
448 dstr_ensure_capacity(dst, new_len + 1);
449 memcpy(dst->array + dst->len, str->array, in_len);
450
451 dst->len = new_len;
452 dst->array[new_len] = 0;
453 }
454
dstr_insert(struct dstr * dst,const size_t idx,const char * array)455 void dstr_insert(struct dstr *dst, const size_t idx, const char *array)
456 {
457 size_t new_len, len;
458 if (!array || !*array)
459 return;
460 if (idx == dst->len) {
461 dstr_cat(dst, array);
462 return;
463 }
464
465 len = strlen(array);
466 new_len = dst->len + len;
467
468 dstr_ensure_capacity(dst, new_len + 1);
469
470 memmove(dst->array + idx + len, dst->array + idx, dst->len - idx + 1);
471 memcpy(dst->array + idx, array, len);
472
473 dst->len = new_len;
474 }
475
dstr_insert_dstr(struct dstr * dst,const size_t idx,const struct dstr * str)476 void dstr_insert_dstr(struct dstr *dst, const size_t idx,
477 const struct dstr *str)
478 {
479 size_t new_len;
480 if (!str->len)
481 return;
482 if (idx == dst->len) {
483 dstr_cat_dstr(dst, str);
484 return;
485 }
486
487 new_len = dst->len + str->len;
488
489 dstr_ensure_capacity(dst, (new_len + 1));
490
491 memmove(dst->array + idx + str->len, dst->array + idx,
492 dst->len - idx + 1);
493 memcpy(dst->array + idx, str->array, str->len);
494
495 dst->len = new_len;
496 }
497
dstr_insert_ch(struct dstr * dst,const size_t idx,const char ch)498 void dstr_insert_ch(struct dstr *dst, const size_t idx, const char ch)
499 {
500 if (idx == dst->len) {
501 dstr_cat_ch(dst, ch);
502 return;
503 }
504
505 dstr_ensure_capacity(dst, (++dst->len + 1));
506 memmove(dst->array + idx + 1, dst->array + idx, dst->len - idx + 1);
507 dst->array[idx] = ch;
508 }
509
dstr_remove(struct dstr * dst,const size_t idx,const size_t count)510 void dstr_remove(struct dstr *dst, const size_t idx, const size_t count)
511 {
512 size_t end;
513 if (!count)
514 return;
515 if (count == dst->len) {
516 dstr_free(dst);
517 return;
518 }
519
520 end = idx + count;
521 if (end == dst->len)
522 dst->array[idx] = 0;
523 else
524 memmove(dst->array + idx, dst->array + end, dst->len - end + 1);
525
526 dst->len -= count;
527 }
528
dstr_printf(struct dstr * dst,const char * format,...)529 void dstr_printf(struct dstr *dst, const char *format, ...)
530 {
531 va_list args;
532 va_start(args, format);
533 dstr_vprintf(dst, format, args);
534 va_end(args);
535 }
536
dstr_catf(struct dstr * dst,const char * format,...)537 void dstr_catf(struct dstr *dst, const char *format, ...)
538 {
539 va_list args;
540 va_start(args, format);
541 dstr_vcatf(dst, format, args);
542 va_end(args);
543 }
544
dstr_vprintf(struct dstr * dst,const char * format,va_list args)545 void dstr_vprintf(struct dstr *dst, const char *format, va_list args)
546 {
547 va_list args_cp;
548 va_copy(args_cp, args);
549
550 int len = vsnprintf(NULL, 0, format, args_cp);
551 va_end(args_cp);
552
553 if (len < 0)
554 len = 4095;
555
556 dstr_ensure_capacity(dst, ((size_t)len) + 1);
557 len = vsnprintf(dst->array, ((size_t)len) + 1, format, args);
558
559 if (!*dst->array) {
560 dstr_free(dst);
561 return;
562 }
563
564 dst->len = len < 0 ? strlen(dst->array) : (size_t)len;
565 }
566
dstr_vcatf(struct dstr * dst,const char * format,va_list args)567 void dstr_vcatf(struct dstr *dst, const char *format, va_list args)
568 {
569 va_list args_cp;
570 va_copy(args_cp, args);
571
572 int len = vsnprintf(NULL, 0, format, args_cp);
573 va_end(args_cp);
574
575 if (len < 0)
576 len = 4095;
577
578 dstr_ensure_capacity(dst, dst->len + ((size_t)len) + 1);
579 len = vsnprintf(dst->array + dst->len, ((size_t)len) + 1, format, args);
580
581 if (!*dst->array) {
582 dstr_free(dst);
583 return;
584 }
585
586 dst->len += len < 0 ? strlen(dst->array + dst->len) : (size_t)len;
587 }
588
dstr_safe_printf(struct dstr * dst,const char * format,const char * val1,const char * val2,const char * val3,const char * val4)589 void dstr_safe_printf(struct dstr *dst, const char *format, const char *val1,
590 const char *val2, const char *val3, const char *val4)
591 {
592 dstr_copy(dst, format);
593 if (val1)
594 dstr_replace(dst, "$1", val1);
595 if (val2)
596 dstr_replace(dst, "$2", val2);
597 if (val3)
598 dstr_replace(dst, "$3", val3);
599 if (val4)
600 dstr_replace(dst, "$4", val4);
601 }
602
dstr_replace(struct dstr * str,const char * find,const char * replace)603 void dstr_replace(struct dstr *str, const char *find, const char *replace)
604 {
605 size_t find_len, replace_len;
606 char *temp;
607
608 if (dstr_is_empty(str))
609 return;
610
611 if (!replace)
612 replace = "";
613
614 find_len = strlen(find);
615 replace_len = strlen(replace);
616 temp = str->array;
617
618 if (replace_len < find_len) {
619 unsigned long count = 0;
620
621 while ((temp = strstr(temp, find)) != NULL) {
622 char *end = temp + find_len;
623 size_t end_len = strlen(end);
624
625 if (end_len) {
626 memmove(temp + replace_len, end, end_len + 1);
627 if (replace_len)
628 memcpy(temp, replace, replace_len);
629 } else {
630 strcpy(temp, replace);
631 }
632
633 temp += replace_len;
634 ++count;
635 }
636
637 if (count)
638 str->len += (replace_len - find_len) * count;
639
640 } else if (replace_len > find_len) {
641 unsigned long count = 0;
642
643 while ((temp = strstr(temp, find)) != NULL) {
644 temp += find_len;
645 ++count;
646 }
647
648 if (!count)
649 return;
650
651 str->len += (replace_len - find_len) * count;
652 dstr_ensure_capacity(str, str->len + 1);
653 temp = str->array;
654
655 while ((temp = strstr(temp, find)) != NULL) {
656 char *end = temp + find_len;
657 size_t end_len = strlen(end);
658
659 if (end_len) {
660 memmove(temp + replace_len, end, end_len + 1);
661 memcpy(temp, replace, replace_len);
662 } else {
663 strcpy(temp, replace);
664 }
665
666 temp += replace_len;
667 }
668
669 } else {
670 while ((temp = strstr(temp, find)) != NULL) {
671 memcpy(temp, replace, replace_len);
672 temp += replace_len;
673 }
674 }
675 }
676
dstr_depad(struct dstr * str)677 void dstr_depad(struct dstr *str)
678 {
679 if (str->array) {
680 str->array = strdepad(str->array);
681 if (*str->array)
682 str->len = strlen(str->array);
683 else
684 dstr_free(str);
685 }
686 }
687
dstr_left(struct dstr * dst,const struct dstr * str,const size_t pos)688 void dstr_left(struct dstr *dst, const struct dstr *str, const size_t pos)
689 {
690 dstr_resize(dst, pos);
691 if (dst != str)
692 memcpy(dst->array, str->array, pos);
693 }
694
dstr_mid(struct dstr * dst,const struct dstr * str,const size_t start,const size_t count)695 void dstr_mid(struct dstr *dst, const struct dstr *str, const size_t start,
696 const size_t count)
697 {
698 struct dstr temp;
699 dstr_init(&temp);
700 dstr_copy_dstr(&temp, str);
701 dstr_ncopy(dst, temp.array + start, count);
702 dstr_free(&temp);
703 }
704
dstr_right(struct dstr * dst,const struct dstr * str,const size_t pos)705 void dstr_right(struct dstr *dst, const struct dstr *str, const size_t pos)
706 {
707 struct dstr temp;
708 dstr_init(&temp);
709 dstr_ncopy(&temp, str->array + pos, str->len - pos);
710 dstr_copy_dstr(dst, &temp);
711 dstr_free(&temp);
712 }
713
dstr_from_mbs(struct dstr * dst,const char * mbstr)714 void dstr_from_mbs(struct dstr *dst, const char *mbstr)
715 {
716 dstr_free(dst);
717 dst->len = os_mbs_to_utf8_ptr(mbstr, 0, &dst->array);
718 }
719
dstr_to_mbs(const struct dstr * str)720 char *dstr_to_mbs(const struct dstr *str)
721 {
722 char *dst;
723 os_mbs_to_utf8_ptr(str->array, str->len, &dst);
724 return dst;
725 }
726
dstr_to_wcs(const struct dstr * str)727 wchar_t *dstr_to_wcs(const struct dstr *str)
728 {
729 wchar_t *dst;
730 os_utf8_to_wcs_ptr(str->array, str->len, &dst);
731 return dst;
732 }
733
dstr_from_wcs(struct dstr * dst,const wchar_t * wstr)734 void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr)
735 {
736 size_t len = wchar_to_utf8(wstr, 0, NULL, 0, 0);
737
738 if (len) {
739 dstr_resize(dst, len);
740 wchar_to_utf8(wstr, 0, dst->array, len + 1, 0);
741 } else {
742 dstr_free(dst);
743 }
744 }
745
dstr_to_upper(struct dstr * str)746 void dstr_to_upper(struct dstr *str)
747 {
748 wchar_t *wstr;
749 wchar_t *temp;
750
751 if (dstr_is_empty(str))
752 return;
753
754 wstr = dstr_to_wcs(str);
755 temp = wstr;
756
757 if (!wstr)
758 return;
759
760 while (*temp) {
761 *temp = (wchar_t)towupper(*temp);
762 temp++;
763 }
764
765 dstr_from_wcs(str, wstr);
766 bfree(wstr);
767 }
768
dstr_to_lower(struct dstr * str)769 void dstr_to_lower(struct dstr *str)
770 {
771 wchar_t *wstr;
772 wchar_t *temp;
773
774 if (dstr_is_empty(str))
775 return;
776
777 wstr = dstr_to_wcs(str);
778 temp = wstr;
779
780 if (!wstr)
781 return;
782
783 while (*temp) {
784 *temp = (wchar_t)towlower(*temp);
785 temp++;
786 }
787
788 dstr_from_wcs(str, wstr);
789 bfree(wstr);
790 }
791