1 /* str.c - string functions
2 *
3 ****************************************************************
4 * Copyright (C) 1998, 2000 Thomas Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11
12 #include "hackerlab/bugs/panic.h"
13 #include "hackerlab/mem/mem.h"
14 #include "hackerlab/char/char-class.h"
15 #include "hackerlab/char/str.h"
16
17
18 /************************************************************************
19 *(h1 "String Functions")
20 *
21 * These functions operate on `strings', defined to be arrays of
22 * 't_uchar' terminated by (and not otherwise containing)
23 * the null character (`(t_uchar)0').
24 *
25 * The functionality described in this function overlaps with some
26 * of the functions in the standard C library defined by Posix,
27 * but there are differences. Read the documentation carefully if
28 * you are replacing uses of Posix functions with Hackerlab functions.
29 */
30 /*(menu)
31 */
32
33 /************************************************************************
34 *(h2 "String Length")
35 *
36 *
37 *
38 */
39
40 /*(c str_length)
41 * size_t str_length (const t_uchar * x);
42 *
43 * Return the length of the 0-terminated string `x'. The length does
44 * not include the 0-byte itself.
45 */
46 size_t
str_length(const t_uchar * x)47 str_length (const t_uchar * x)
48 {
49 size_t q;
50
51 if (!x)
52 return 0;
53 q = 0;
54 while (*x)
55 ++x, ++q;
56
57 return q;
58 }
59
60
61 /*(c str_length_n)
62 * size_t str_length_n (const t_uchar * x, size_t n);
63 *
64 * Return the length of the 0-terminated string `x' but not more than
65 * `n'. The length does not include the 0-byte itself.
66 *
67 * If `x' is longer than `n' bytes, return `n'.
68 */
69 size_t
str_length_n(const t_uchar * x,size_t n)70 str_length_n (const t_uchar * x, size_t n)
71 {
72 size_t q;
73
74 if (!x)
75 return 0;
76 q = 0;
77 while ((q < n) && *x)
78 ++x, ++q;
79
80 return q;
81 }
82
83
84 /************************************************************************
85 *(h2 "Computing Hash Values From Strings")
86 *
87 */
88
89 /*(c str_hash)
90 * unsigned long str_hash (const t_uchar * chr, size_t len);
91 *
92 * Compute an `unsigned long' hash value for a 0-terminated string.
93 * This computes the same hash value as
94 *
95 * str_hash_n (chr, str_length (chr));
96 *
97 */
98 unsigned long
str_hash(const t_uchar * chr)99 str_hash (const t_uchar * chr)
100 {
101 unsigned long result;
102
103 result = 0;
104 while (*chr)
105 {
106 result = *chr + (result << 3) + (result >> (8 * sizeof (result) - 3));
107 ++chr;
108 }
109
110 return result;
111 }
112
113
114 /*(c str_hash_n)
115 * unsigned long str_hash_n (const t_uchar * chr, size_t len);
116 *
117 * Compute an `unsigned long' hash value for a string of the indicated
118 * length..
119 */
120 unsigned long
str_hash_n(const t_uchar * chr,size_t len)121 str_hash_n (const t_uchar * chr, size_t len)
122 {
123 unsigned long result;
124
125 result = 0;
126 while (len--)
127 {
128 result = *chr + (result << 3) + (result >> (8 * sizeof (result) - 3));
129 ++chr;
130 }
131
132 return result;
133 }
134
135
136
137 /************************************************************************
138 *(h2 "Simple String Searching and Parsing")
139 *
140 */
141
142 /*(c str_chr_index)
143 * t_uchar * str_chr_index (const t_uchar * s, int c);
144 *
145 * Return the position in 0-terminated string `s' of the first
146 * occurence of `c'. Return 0 if `c' does not occur in `s'.
147 */
148 t_uchar *
str_chr_index(const t_uchar * s,int c)149 str_chr_index (const t_uchar * s, int c)
150 {
151 while (*s)
152 {
153 if (*s == c)
154 return (t_uchar *)s;
155 ++s;
156 }
157 if (c == 0)
158 return (t_uchar *)s;
159 return 0;
160 }
161
162
163 /*(c str_chr_rindex)
164 * t_uchar * str_chr_rindex (const t_uchar * s, int c);
165 *
166 * Return the position in 0-terminated string `s' of the last
167 * occurence of `c'. Return 0 if `c' does not occur in `s'.
168 */
169 t_uchar *
str_chr_rindex(const t_uchar * s,int c)170 str_chr_rindex (const t_uchar * s, int c)
171 {
172 const t_uchar * best;
173
174 best = 0;
175 while (*s)
176 {
177 if (*s == c)
178 best = s;
179 ++s;
180 }
181 if (c == 0)
182 return (t_uchar *)s;
183 return (t_uchar *)best;
184 }
185
186
187 /*(c str_chr_index_n)
188 * t_uchar * str_chr_index_n (const t_uchar * s, size_t n, int c);
189 *
190 * Return the position in length `n' string `s' of the first occurence
191 * of `c'. Return 0 if `c' does not occur in `s'.
192 */
193 t_uchar *
str_chr_index_n(const t_uchar * s,size_t n,int c)194 str_chr_index_n (const t_uchar * s, size_t n, int c)
195 {
196 while (n)
197 {
198 if (*s == c)
199 return (t_uchar *)s;
200 if (!*s)
201 return 0;
202 ++s;
203 --n;
204 }
205 return 0;
206 }
207
208
209 /*(c str_chr_rindex_n)
210 * t_uchar * str_chr_rindex_n (const t_uchar * s, size_t n, int c);
211 *
212 * Return the position in length `n' string `s' of the last occurence
213 * of `c'. Return 0 if `c' does not occur in `s'.
214 */
215 t_uchar *
str_chr_rindex_n(const t_uchar * s,size_t n,int c)216 str_chr_rindex_n (const t_uchar * s, size_t n, int c)
217 {
218 s += n - 1;
219 while (n)
220 {
221 if (*s == c)
222 return (t_uchar *)s;
223 --s;
224 --n;
225 }
226 return 0;
227 }
228
229
230
231 /*(c str_separate)
232 * t_uchar * str_separate (t_uchar ** stringp, t_uchar * delims);
233 *
234 * Find the first occurence of a character from `delims' in `*stringp',
235 * replace that character with 0, set `*stringp' the address of the next
236 * character after that, and return the value that `*stringp' had on entry.
237 *
238 * If no delimeter is found in `*stringp', set `*stringp' to 0 and return
239 * the value on entry of `*stringp'.
240 *
241 * If `*stringp' is 0, return 0.
242 *
243 * If `delims' is 0, set `*stringp' to 0, and return the value of `*stringp'
244 * on entry.
245 */
246 t_uchar *
str_separate(t_uchar ** stringp,t_uchar * delims)247 str_separate (t_uchar ** stringp, t_uchar * delims)
248 {
249 t_uchar * string;
250 t_uchar * pos;
251
252 string = *stringp;
253
254 if (!string)
255 return 0;
256
257 if (!delims)
258 {
259 *stringp = 0;
260 return string;
261 }
262
263 pos = string;
264
265 while (1)
266 {
267 if (!*pos)
268 {
269 *stringp = 0;
270 return string;
271 }
272
273 if (str_chr_index (delims, *pos))
274 {
275 *pos = 0;
276 *stringp = pos + 1;
277 return string;
278 }
279 ++pos;
280 }
281 }
282
283
284
285 /************************************************************************
286 *(h2 "String Comparisons")
287 *
288 *
289 *
290 */
291
292 /*(c str_cmp)
293 * int str_cmp (const t_uchar * a, const t_uchar * b);
294 *
295 * Compare strings `a' and `b' returning -1 if `a' is lexically first,
296 * 0 if the two strings are equal, 1 if `b' is lexically first.
297 */
298 int
str_cmp(const t_uchar * a,const t_uchar * b)299 str_cmp (const t_uchar * a, const t_uchar * b)
300 {
301 if ((!a || !*a) && (!b || !*b))
302 return 0;
303
304 if (!b || !*b)
305 return 1;
306
307 if (!a || !a)
308 return -1;
309
310 while ((*a == *b) && *a)
311 {
312 ++a;
313 ++b;
314 }
315
316 if (*a == *b)
317 return 0;
318 else if (*a < *b)
319 return -1;
320 else
321 return 1;
322 }
323
324
325 /*(c str_cmp_n)
326 * int str_cmp_n (const t_uchar * a,
327 * size_t a_l,
328 * const t_uchar * b,
329 * size_t b_l);
330 *
331 * Compare strings `a' (length `a_l') and `b' (length `b_l') returning
332 * -1 if `a' is lexically first, 0 if the two strings are equal, 1 if
333 * `b' is lexically first.
334 *
335 */
336 int
str_cmp_n(const t_uchar * a,size_t a_l,const t_uchar * b,size_t b_l)337 str_cmp_n (const t_uchar * a, size_t a_l, const t_uchar * b, size_t b_l)
338 {
339 size_t l;
340
341 l = ((a_l < b_l) ? a_l : b_l);
342 while (l)
343 {
344 t_uchar ac;
345 t_uchar bc;
346
347 ac = *a++;
348 bc = *b++;
349 if (ac == bc)
350 {
351 --l;
352 continue;
353 }
354 else
355 {
356 return ((ac < bc) ? -1 : 1);
357 }
358 }
359 if (a_l < b_l)
360 return -1;
361 else if (b_l < a_l)
362 return 1;
363 else
364 return 0;
365 }
366
367
368 /*(c str_cmp_prefix)
369 * int str_cmp_prefix (const t_uchar * prefix, const t_uchar * s);
370 *
371 * Compare strings `prefix' and `s'. If `prefix' is a prefix of `s',
372 * return 0. Otherwise, if `prefix' is lexically first, return -1;
373 * if `s' is lexically first, return 1.
374 */
375 int
str_cmp_prefix(const t_uchar * prefix,const t_uchar * s)376 str_cmp_prefix (const t_uchar * prefix, const t_uchar * s)
377 {
378 if (!prefix)
379 return 0;
380
381 if (!s)
382 {
383 if (!*prefix)
384 return 0;
385 else
386 return 1;
387 }
388
389 while (*prefix)
390 {
391 if (*s < *prefix)
392 return 1;
393 else if (*s > *prefix)
394 return -1;
395 else
396 ++prefix, ++s;
397 }
398 return 0;
399 }
400
401
402 /*(c str_cmp_prefix_n)
403 * int str_cmp_prefix_n (const t_uchar * prefix,
404 * size_t prefix_len,
405 * const t_uchar * s,
406 * size_t s_len);
407 *
408 * Compare strings `prefix' and `s', of the indicated lengths. If
409 * `prefix' is a prefix of `s', return 0. Otherwise, if `prefix' is
410 * lexically first, return -1; if `s' is lexically first, return 1.
411 */
412 int
str_cmp_prefix_n(const t_uchar * prefix,size_t prefix_len,const t_uchar * s,size_t s_len)413 str_cmp_prefix_n (const t_uchar * prefix,
414 size_t prefix_len,
415 const t_uchar * s,
416 size_t s_len)
417 {
418 if (!prefix_len)
419 return 0;
420
421 if (!s_len)
422 return 1;
423
424 while (prefix_len && s_len)
425 {
426 if (*s < *prefix)
427 return 1;
428 else if (*s > *prefix)
429 return -1;
430 else
431 {
432 ++prefix;
433 ++s;
434 --prefix_len;
435 --s_len;
436 }
437 }
438
439 return !!prefix_len;
440 }
441
442
443 /************************************************************************
444 *(h2 "String Comparisons Ignoring Case")
445 *
446 */
447
448 /*(c str_casecmp)
449 * int str_casecmp (const t_uchar * a, const t_uchar * b);
450 *
451 * Compare strings `a' and `b' ignoring case, returning -1 if `a' is
452 * lexically first, 0 if the two strings are equal, 1 if `b' is
453 * lexically first.
454 */
455 int
str_casecmp(const t_uchar * a,const t_uchar * b)456 str_casecmp (const t_uchar * a, const t_uchar * b)
457 {
458 if ((!a || !*a) && (!b || !*b))
459 return 0;
460
461 if (!b || !*b)
462 return 1;
463
464 if (!a || !*a)
465 return -1;
466
467 while ((char_to_lower(*a) == char_to_lower(*b)) && *a)
468 {
469 ++a;
470 ++b;
471 }
472
473 if (char_to_lower(*a) == char_to_lower(*b))
474 return 0;
475 else if (char_to_lower(*a) < char_to_lower(*b))
476 return -1;
477 else
478 return 1;
479 }
480
481
482 /*(c str_casecmp_n)
483 * int str_casecmp_n (const t_uchar * a, size_t a_l,
484 * const t_uchar * b, size_t b_l);
485 *
486 * Compare strings `a' (length `a_l') and `b' (length `b_l') ignoring
487 * case returning -1 if `a' is lexically first, 0 if the two strings
488 * are equal, 1 if `b' is lexically first.
489 */
490 int
str_casecmp_n(const t_uchar * a,size_t a_l,const t_uchar * b,size_t b_l)491 str_casecmp_n (const t_uchar * a, size_t a_l,
492 const t_uchar * b, size_t b_l)
493 {
494 size_t l;
495 l = ((a_l < b_l) ? a_l : b_l);
496 while (l)
497 {
498 t_uchar ac;
499 t_uchar bc;
500
501 ac = char_to_lower(*a++);
502 bc = char_to_lower(*b++);
503 if (ac < bc)
504 return -1;
505 else if (ac > bc)
506 return 1;
507 else if (!ac)
508 return 0;
509 --l;
510 }
511 if (a_l < b_l)
512 return -1;
513 else if (b_l < a_l)
514 return 1;
515 else
516 return 0;
517 }
518
519
520 /*(c str_casecmp_prefix)
521 * int str_casecmp_prefix (const t_uchar * prefix, const t_uchar * s);
522 *
523 * Compare strings `prefix' and `s', ignoring case. If `prefix' is a
524 * prefix of `s', return 0. Otherwise, if `prefix' is lexically
525 * first, return -1; if `s' is lexically first, return 1.
526 */
527 int
str_casecmp_prefix(const t_uchar * prefix,const t_uchar * s)528 str_casecmp_prefix (const t_uchar * prefix, const t_uchar * s)
529 {
530 if (!prefix)
531 return 0;
532
533 if (!s)
534 {
535 if (!*prefix)
536 return 0;
537 else
538 return 1;
539 }
540 while (*prefix)
541 {
542 if (char_to_lower(*s) < char_to_lower(*prefix))
543 return 1;
544 else if (char_to_lower(*s) > char_to_lower(*prefix))
545 return -1;
546 else
547 ++prefix, ++s;
548 }
549 return 0;
550 }
551
552
553
554 /*(c str_casecmp_prefix_n)
555 * int str_casecmp_prefix_n (const t_uchar * prefix,
556 * size_t prefix_len,
557 * const t_uchar * s,
558 * size_t s_len);
559 *
560 * Compare strings `prefix' and `s', of the indicated lengths,
561 * ignoring case. If `prefix' is a prefix of `s', return 0.
562 * Otherwise, if `prefix' is lexically first, return -1; if `s' is
563 * lexically first, return 1.
564 */
565 int
str_casecmp_prefix_n(const t_uchar * prefix,size_t prefix_len,const t_uchar * s,size_t s_len)566 str_casecmp_prefix_n (const t_uchar * prefix,
567 size_t prefix_len,
568 const t_uchar * s,
569 size_t s_len)
570 {
571 if (!prefix_len)
572 return 0;
573
574 if (!s_len)
575 return 1;
576
577 while (prefix_len && s_len)
578 {
579 if (char_to_lower(*s) < char_to_lower (*prefix))
580 return 1;
581 else if (char_to_lower (*s) > char_to_lower (*prefix))
582 return -1;
583 else
584 {
585 ++prefix;
586 ++s;
587 --prefix_len;
588 --s_len;
589 }
590 }
591
592 return !!prefix_len;
593 }
594
595
596 /************************************************************************
597 *(h2 "String Copying")
598 *
599 */
600
601 /*(c str_cpy)
602 * t_uchar * str_cpy (t_uchar * to, const t_uchar * from);
603 *
604 * Copy the 0-terminated string `from' to `to'. `from' and `to'
605 * should not overlap.
606 *
607 * Returns `to'.
608 */
609 t_uchar *
str_cpy(t_uchar * to,const t_uchar * from)610 str_cpy (t_uchar * to, const t_uchar * from)
611 {
612 t_uchar * answer;
613 answer = to;
614 if (from)
615 {
616 while (*from)
617 *to++ = *from++;
618 }
619 *to = 0;
620 return answer;
621 }
622
623
624 /*(c str_cpy_n)
625 * t_uchar * str_cpy_n (t_uchar * to,
626 * const t_uchar * from,
627 * size_t n);
628 *
629 * Copy up-to `n' characters from `from' to `to'.
630 *
631 * Add a final 0 to `to'.
632 *
633 * \Warning:/ This function is different from `strncpy'. `strncpy'
634 * always stores exactly `n' characters in `to', padding the result
635 * with 0 if a 0 character is encountered in `from' before `n'
636 * characters are written. This function stores up to `n+1' characters:
637 * up to `n' non-0 characters from `from', plus a final 0.
638 *
639 * Returns `to'.
640 */
641 t_uchar *
str_cpy_n(t_uchar * to,const t_uchar * from,size_t n)642 str_cpy_n (t_uchar * to,
643 const t_uchar * from,
644 size_t n)
645 {
646 t_uchar * answer;
647
648 answer = to;
649 if (from)
650 {
651 while (n && *from)
652 {
653 *to++ = *from++;
654 --n;
655 }
656 }
657 *to++ = 0;
658 return answer;
659 }
660
661
662
663 /************************************************************************
664 *(h2 "String Concatenation")
665 *
666 *
667 *
668 */
669
670 /*(c str_cat)
671 * t_uchar * str_cat (t_uchar * to, const t_uchar * from);
672 *
673 * Append the 0-terminated string `from' to the 0-terminated string
674 * `to'. The strings should not overlap.
675 *
676 * Returns `to'.
677 */
678 t_uchar *
str_cat(t_uchar * to,const t_uchar * from)679 str_cat (t_uchar * to, const t_uchar * from)
680 {
681 t_uchar * answer;
682
683 answer = to;
684
685 if (from)
686 {
687 while (*to)
688 ++to;
689
690 while (*from)
691 *to++ = *from++;
692
693 *to = 0;
694 }
695
696 return answer;
697 }
698
699
700 /*(c str_cat_n)
701 * t_uchar * str_cat_n (t_uchar * to,
702 * const t_uchar * from,
703 * size_t n);
704 *
705 * Append at most `n' characters of the 0-terminated string `from' to
706 * the 0-terminated string `to'. The strings should not overlap.
707 * Add a final 0 (thus writing up to `n + 1' characters in `to',
708 * starting from the position of the final 0 in `to' on entry).
709 *
710 * Returns `to'.
711 */
712 t_uchar *
str_cat_n(t_uchar * to,const t_uchar * from,size_t n)713 str_cat_n (t_uchar * to,
714 const t_uchar * from,
715 size_t n)
716 {
717 t_uchar * answer;
718
719 answer = to;
720
721 while (*to)
722 ++to;
723
724 while (n && *from)
725 {
726 *to++ = *from++;
727 --n;
728 }
729
730 *to = 0;
731 return answer;
732 }
733
734
735
736 /************************************************************************
737 *(h2 "String Allocators")
738 *
739 *
740 */
741
742
743 /*(c str_save)
744 * t_uchar * str_save (alloc_limits limits, const t_uchar * str);
745 *
746 * Allocate a copy of the 0-terminated string `str'.
747 *
748 * Allocate storage according to `limits'. (See xref:"Allocation
749 * With Limitations".)
750 */
751 t_uchar *
str_save(alloc_limits limits,const t_uchar * str)752 str_save (alloc_limits limits, const t_uchar * str)
753 {
754 t_uchar * it;
755 size_t len;
756
757 len = str_length (str);
758
759 invariant (len + 1);
760
761 it = (t_uchar *)lim_malloc (limits, len + 1);
762 if (!it)
763 return 0;
764 str_cpy (it, str);
765 return it;
766 }
767
768
769 /*(c str_save_n)
770 * t_uchar * str_save_n (alloc_limits limits,
771 * const t_uchar * str,
772 * size_t len);
773 *
774 * Allocate a copy of the n-byte string `str'.
775 * Add one byte to the new string and store 0 in that byte.
776 *
777 * Allocate storage according to `limits'. (See xref:"Allocation
778 * With Limitations".)
779 */
780 t_uchar *
str_save_n(alloc_limits limits,const t_uchar * str,size_t len)781 str_save_n (alloc_limits limits,
782 const t_uchar * str,
783 size_t len)
784 {
785 t_uchar * it;
786
787 invariant (len + 1);
788
789 it = (t_uchar *)lim_malloc (limits, len + 1);
790 if (!it)
791 return 0;
792 mem_move (it, str, len);
793 it[len] = 0;
794 return it;
795 }
796
797
798 /*(c str_save_trimming)
799 * t_uchar * str_save_trimming (alloc_limits limits, const t_uchar * str);
800 *
801 * Allocate a copy of the 0-terminated string `str', discarding
802 * leading and trailing whitespace from the copy.
803 *
804 * Allocate storage according to `limits'. (See xref:"Allocation
805 * With Limitations".)
806 */
807 t_uchar *
str_save_trimming(alloc_limits limits,const t_uchar * str)808 str_save_trimming (alloc_limits limits, const t_uchar * str)
809 {
810 const t_uchar * start;
811 const t_uchar * scan;
812 const t_uchar * end;
813 size_t len;
814 t_uchar * it;
815
816 if (!str)
817 start = scan = end = 0;
818 else
819 {
820 for (start = str; *start && char_is_space (*start); ++start)
821 ;
822
823 end = start;
824 for (scan = start; *scan; ++scan)
825 {
826 if (!char_is_space (*scan))
827 end = scan + 1;
828 }
829 }
830
831 len = (end - start);
832
833 invariant (len + 1);
834
835 it = (t_uchar *)lim_malloc (limits, len + 1);
836 if (!it)
837 return 0;
838 mem_move (it, start, len);
839 it[len] = 0;
840 return it;
841 }
842
843
844 /*(c str_save_trimming_n)
845 * t_uchar * str_save_trimming_n (alloc_limits limits,
846 * const t_uchar * str,
847 * size_t len);
848 *
849 * Allocate a copy of the n-byte string `str'. Leading and
850 * trailing whitespace are discarded from the copy (which may
851 * therefore be of length less than `n').
852 *
853 * The copy includes a trailing 0.
854 *
855 * Allocate storage according to `limits'. (See xref:"Allocation
856 * With Limitations".)
857 */
858 t_uchar *
str_save_trimming_n(alloc_limits limits,const t_uchar * str,size_t len)859 str_save_trimming_n (alloc_limits limits,
860 const t_uchar * str,
861 size_t len)
862 {
863 t_uchar * it;
864
865 while (len && char_is_space (*str))
866 {
867 ++str;
868 --len;
869 }
870
871 while (len && char_is_space (str[len - 1]))
872 {
873 --len;
874 }
875
876
877 invariant (len + 1);
878
879 it = (t_uchar *)lim_malloc (limits, len + 1);
880 if (!it)
881 return 0;
882 mem_move (it, str, len);
883 it[len] = 0;
884 return it;
885 }
886
887
888 /*(c str_alloc_cat)
889 * t_uchar * str_alloc_cat (alloc_limits limits,
890 * const t_uchar * str1,
891 * const t_uchar * str2);
892 *
893 * Allocate a new string large enough to hold the concatenation of
894 * 0-terminated strings `str1' and `str2' (including a final 0).
895 * Initialize the new string with the concatenation of `str1' and
896 * `str2'.
897 *
898 * Allocate storage according to `limits'. (See xref:"Allocation
899 * With Limitations".)
900 */
901 t_uchar *
str_alloc_cat(alloc_limits limits,const t_uchar * str1,const t_uchar * str2)902 str_alloc_cat (alloc_limits limits,
903 const t_uchar * str1,
904 const t_uchar * str2)
905 {
906 if (!str1 && !str2)
907 return 0;
908 if (!str1)
909 return str_save (limits, str2);
910 if (!str2)
911 return str_save (limits, str1);
912 {
913 t_uchar * it;
914 size_t len;
915
916 len = str_length (str1) + str_length (str2) + 1;
917 it = (t_uchar *)lim_malloc (limits, len);
918 if (!it)
919 return 0;
920 str_cpy (it, str1);
921 str_cat (it, str2);
922 return it;
923 }
924 }
925
926
927 /*(c str_alloc_cat_n)
928 * t_uchar * str_alloc_cat_n (alloc_limits limits,
929 * const t_uchar * str1,
930 * const t_uchar * str2,
931 * size_t n);
932 *
933 * Allocate a new 0-terminated string large enough to hold the
934 * concatenation of 0-terminated strings `str1' and `str2',
935 * considering at most `n' characters from `str2'.
936 *
937 * Initialize the new string with the concatenation of `str1' and
938 * up to `n' characters of `str2'. Append a final 0.
939 *
940 * Allocate storage according to `limits'. (See xref:"Allocation
941 * With Limitations".)
942 */
943 t_uchar *
str_alloc_cat_n(alloc_limits limits,const t_uchar * str1,const t_uchar * str2,size_t n)944 str_alloc_cat_n (alloc_limits limits,
945 const t_uchar * str1,
946 const t_uchar * str2,
947 size_t n)
948 {
949 if (!str1 && !str2)
950 return 0;
951 if (!str1)
952 return str_save_n (limits, str2, n);
953 if (!str2)
954 return str_save (limits, str1);
955 {
956 t_uchar * it;
957 size_t len;
958
959 len = str_length (str1) + str_length_n (str2, n) + 1;
960 it = (t_uchar *)lim_malloc (limits, len);
961 if (!it)
962 return 0;
963 str_cpy (it, str1);
964 str_cat_n (it, str2, n);
965 return it;
966 }
967 }
968
969
970
971 /*(c str_realloc_cat)
972 * t_uchar * str_realloc_cat (alloc_limits limits,
973 * t_uchar * str1,
974 * const t_uchar * str2);
975 *
976 * Reallocate `str1`' to be large enough to hold the concatenation of
977 * 0-terminated strings `str1' and `str2' (including a final 0).
978 * Initialize the new string with the concatenation of `str1' and
979 * `str2'.
980 *
981 * Allocate storage according to `limits'. (See xref:"Allocation
982 * With Limitations".)
983 */
984 t_uchar *
str_realloc_cat(alloc_limits limits,t_uchar * str1,const t_uchar * str2)985 str_realloc_cat (alloc_limits limits,
986 t_uchar * str1,
987 const t_uchar * str2)
988 {
989 if (!str1 && !str2)
990 return 0;
991
992 if (!str1)
993 return str_save (limits, str2);
994
995 if (!str2)
996 return str1;
997
998 {
999 t_uchar * it;
1000 size_t len;
1001
1002 len = str_length (str1) + str_length (str2) + 1;
1003 it = (t_uchar *)lim_realloc (limits, str1, len);
1004 if (!it)
1005 return 0;
1006 str_cat (it, str2);
1007 return it;
1008 }
1009 }
1010
1011
1012 /*(c str_realloc_cat_n)
1013 * t_uchar * str_realloc_cat_n (alloc_limits limits,
1014 * t_uchar * str1,
1015 * const t_uchar * str2,
1016 * size_t n);
1017 *
1018 * Reallocate `str' to be large enough to hold the
1019 * concatenation of 0-terminated strings `str1' and `str2',
1020 * considering at most `n' characters from `str2'.
1021 *
1022 * Initialize the new string with the concatenation of `str1' and
1023 * up to `n' characters of `str2'. Append a final 0.
1024 *
1025 * Allocate storage according to `limits'. (See xref:"Allocation
1026 * With Limitations".)
1027 */
1028 t_uchar *
str_realloc_cat_n(alloc_limits limits,t_uchar * str1,const t_uchar * str2,size_t n)1029 str_realloc_cat_n (alloc_limits limits,
1030 t_uchar * str1,
1031 const t_uchar * str2,
1032 size_t n)
1033 {
1034 if (!str1 && !str2)
1035 return 0;
1036
1037 if (!str1)
1038 return str_save_n (limits, str2, n);
1039
1040 if (!str2)
1041 return str1;
1042
1043 {
1044 t_uchar * it;
1045 size_t len;
1046
1047 len = str_length (str1) + str_length_n (str2, n) + 1;
1048 it = (t_uchar *)lim_realloc (limits, str1, len);
1049 if (!it)
1050 return 0;
1051 str_cat_n (it, str2, n);
1052 return it;
1053 }
1054 }
1055
1056 size_t
str_occurences(t_uchar * s,int c)1057 str_occurences (t_uchar * s, int c)
1058 {
1059 size_t answer;
1060
1061 answer = 0;
1062 while (*s)
1063 {
1064 if (*s == c)
1065 ++answer;
1066 ++s;
1067 }
1068 return answer;
1069 }
1070
1071
1072 /*(include-documentation "str-many.c")
1073 */
1074
1075