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