chiark / gitweb /
bdaa42084b423c36a72b9be91710b25f588d93f3
[elogind.git] / src / basic / string-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <stdarg.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdio_ext.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "alloc-util.h"
17 //#include "escape.h"
18 #include "gunicode.h"
19 //#include "locale-util.h"
20 #include "macro.h"
21 #include "string-util.h"
22 //#include "terminal-util.h"
23 #include "utf8.h"
24 #include "util.h"
25 //#include "fileio.h"
26
27 int strcmp_ptr(const char *a, const char *b) {
28
29         /* Like strcmp(), but tries to make sense of NULL pointers */
30         if (a && b)
31                 return strcmp(a, b);
32
33         if (!a && b)
34                 return -1;
35
36         if (a && !b)
37                 return 1;
38
39         return 0;
40 }
41
42 char* endswith(const char *s, const char *postfix) {
43         size_t sl, pl;
44
45         assert(s);
46         assert(postfix);
47
48         sl = strlen(s);
49         pl = strlen(postfix);
50
51         if (pl == 0)
52                 return (char*) s + sl;
53
54         if (sl < pl)
55                 return NULL;
56
57         if (memcmp(s + sl - pl, postfix, pl) != 0)
58                 return NULL;
59
60         return (char*) s + sl - pl;
61 }
62
63 char* endswith_no_case(const char *s, const char *postfix) {
64         size_t sl, pl;
65
66         assert(s);
67         assert(postfix);
68
69         sl = strlen(s);
70         pl = strlen(postfix);
71
72         if (pl == 0)
73                 return (char*) s + sl;
74
75         if (sl < pl)
76                 return NULL;
77
78         if (strcasecmp(s + sl - pl, postfix) != 0)
79                 return NULL;
80
81         return (char*) s + sl - pl;
82 }
83
84 char* first_word(const char *s, const char *word) {
85         size_t sl, wl;
86         const char *p;
87
88         assert(s);
89         assert(word);
90
91         /* Checks if the string starts with the specified word, either
92          * followed by NUL or by whitespace. Returns a pointer to the
93          * NUL or the first character after the whitespace. */
94
95         sl = strlen(s);
96         wl = strlen(word);
97
98         if (sl < wl)
99                 return NULL;
100
101         if (wl == 0)
102                 return (char*) s;
103
104         if (memcmp(s, word, wl) != 0)
105                 return NULL;
106
107         p = s + wl;
108         if (*p == 0)
109                 return (char*) p;
110
111         if (!strchr(WHITESPACE, *p))
112                 return NULL;
113
114         p += strspn(p, WHITESPACE);
115         return (char*) p;
116 }
117
118 static size_t strcspn_escaped(const char *s, const char *reject) {
119         bool escaped = false;
120         int n;
121
122         for (n=0; s[n]; n++) {
123                 if (escaped)
124                         escaped = false;
125                 else if (s[n] == '\\')
126                         escaped = true;
127                 else if (strchr(reject, s[n]))
128                         break;
129         }
130
131         /* if s ends in \, return index of previous char */
132         return n - escaped;
133 }
134
135 /* Split a string into words. */
136 const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
137         const char *current;
138
139         current = *state;
140
141         if (!*current) {
142                 assert(**state == '\0');
143                 return NULL;
144         }
145
146         current += strspn(current, separator);
147         if (!*current) {
148                 *state = current;
149                 return NULL;
150         }
151
152         if (quoted && strchr("\'\"", *current)) {
153                 char quotechars[2] = {*current, '\0'};
154
155                 *l = strcspn_escaped(current + 1, quotechars);
156                 if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
157                     (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
158                         /* right quote missing or garbage at the end */
159                         *state = current;
160                         return NULL;
161                 }
162                 *state = current++ + *l + 2;
163         } else if (quoted) {
164                 *l = strcspn_escaped(current, separator);
165                 if (current[*l] && !strchr(separator, current[*l])) {
166                         /* unfinished escape */
167                         *state = current;
168                         return NULL;
169                 }
170                 *state = current + *l;
171         } else {
172                 *l = strcspn(current, separator);
173                 *state = current + *l;
174         }
175
176         return current;
177 }
178
179 char *strnappend(const char *s, const char *suffix, size_t b) {
180         size_t a;
181         char *r;
182
183         if (!s && !suffix)
184                 return strdup("");
185
186         if (!s)
187                 return strndup(suffix, b);
188
189         if (!suffix)
190                 return strdup(s);
191
192         assert(s);
193         assert(suffix);
194
195         a = strlen(s);
196         if (b > ((size_t) -1) - a)
197                 return NULL;
198
199         r = new(char, a+b+1);
200         if (!r)
201                 return NULL;
202
203         memcpy(r, s, a);
204         memcpy(r+a, suffix, b);
205         r[a+b] = 0;
206
207         return r;
208 }
209
210 char *strappend(const char *s, const char *suffix) {
211         return strnappend(s, suffix, strlen_ptr(suffix));
212 }
213
214 char *strjoin_real(const char *x, ...) {
215         va_list ap;
216         size_t l;
217         char *r, *p;
218
219         va_start(ap, x);
220
221         if (x) {
222                 l = strlen(x);
223
224                 for (;;) {
225                         const char *t;
226                         size_t n;
227
228                         t = va_arg(ap, const char *);
229                         if (!t)
230                                 break;
231
232                         n = strlen(t);
233                         if (n > ((size_t) -1) - l) {
234                                 va_end(ap);
235                                 return NULL;
236                         }
237
238                         l += n;
239                 }
240         } else
241                 l = 0;
242
243         va_end(ap);
244
245         r = new(char, l+1);
246         if (!r)
247                 return NULL;
248
249         if (x) {
250                 p = stpcpy(r, x);
251
252                 va_start(ap, x);
253
254                 for (;;) {
255                         const char *t;
256
257                         t = va_arg(ap, const char *);
258                         if (!t)
259                                 break;
260
261                         p = stpcpy(p, t);
262                 }
263
264                 va_end(ap);
265         } else
266                 r[0] = 0;
267
268         return r;
269 }
270
271 char *strstrip(char *s) {
272         char *e;
273
274         if (!s)
275                 return NULL;
276
277         /* Drops trailing whitespace. Modifies the string in
278          * place. Returns pointer to first non-space character */
279
280         s += strspn(s, WHITESPACE);
281
282         for (e = strchr(s, 0); e > s; e --)
283                 if (!strchr(WHITESPACE, e[-1]))
284                         break;
285
286         *e = 0;
287
288         return s;
289 }
290
291 #if 0 /// UNNEEDED by elogind
292 char *delete_chars(char *s, const char *bad) {
293         char *f, *t;
294
295         /* Drops all specified bad characters, regardless where in the string */
296
297         if (!s)
298                 return NULL;
299
300         if (!bad)
301                 bad = WHITESPACE;
302
303         for (f = s, t = s; *f; f++) {
304                 if (strchr(bad, *f))
305                         continue;
306
307                 *(t++) = *f;
308         }
309
310         *t = 0;
311
312         return s;
313 }
314 #endif // 0
315
316 char *delete_trailing_chars(char *s, const char *bad) {
317         char *p, *c = s;
318
319         /* Drops all specified bad characters, at the end of the string */
320
321         if (!s)
322                 return NULL;
323
324         if (!bad)
325                 bad = WHITESPACE;
326
327         for (p = s; *p; p++)
328                 if (!strchr(bad, *p))
329                         c = p + 1;
330
331         *c = 0;
332
333         return s;
334 }
335
336 char *truncate_nl(char *s) {
337         assert(s);
338
339         s[strcspn(s, NEWLINE)] = 0;
340         return s;
341 }
342
343 #if 0 /// UNNEEDED by elogind
344 char ascii_tolower(char x) {
345
346         if (x >= 'A' && x <= 'Z')
347                 return x - 'A' + 'a';
348
349         return x;
350 }
351
352 char ascii_toupper(char x) {
353
354         if (x >= 'a' && x <= 'z')
355                 return x - 'a' + 'A';
356
357         return x;
358 }
359
360 char *ascii_strlower(char *t) {
361         char *p;
362
363         assert(t);
364
365         for (p = t; *p; p++)
366                 *p = ascii_tolower(*p);
367
368         return t;
369 }
370
371 char *ascii_strupper(char *t) {
372         char *p;
373
374         assert(t);
375
376         for (p = t; *p; p++)
377                 *p = ascii_toupper(*p);
378
379         return t;
380 }
381
382 char *ascii_strlower_n(char *t, size_t n) {
383         size_t i;
384
385         if (n <= 0)
386                 return t;
387
388         for (i = 0; i < n; i++)
389                 t[i] = ascii_tolower(t[i]);
390
391         return t;
392 }
393
394 int ascii_strcasecmp_n(const char *a, const char *b, size_t n) {
395
396         for (; n > 0; a++, b++, n--) {
397                 int x, y;
398
399                 x = (int) (uint8_t) ascii_tolower(*a);
400                 y = (int) (uint8_t) ascii_tolower(*b);
401
402                 if (x != y)
403                         return x - y;
404         }
405
406         return 0;
407 }
408
409 int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m) {
410         int r;
411
412         r = ascii_strcasecmp_n(a, b, MIN(n, m));
413         if (r != 0)
414                 return r;
415
416         if (n < m)
417                 return -1;
418         else if (n > m)
419                 return 1;
420         else
421                 return 0;
422 }
423
424 bool chars_intersect(const char *a, const char *b) {
425         const char *p;
426
427         /* Returns true if any of the chars in a are in b. */
428         for (p = a; *p; p++)
429                 if (strchr(b, *p))
430                         return true;
431
432         return false;
433 }
434 #endif // 0
435
436 bool string_has_cc(const char *p, const char *ok) {
437         const char *t;
438
439         assert(p);
440
441         /*
442          * Check if a string contains control characters. If 'ok' is
443          * non-NULL it may be a string containing additional CCs to be
444          * considered OK.
445          */
446
447         for (t = p; *t; t++) {
448                 if (ok && strchr(ok, *t))
449                         continue;
450
451                 if (*t > 0 && *t < ' ')
452                         return true;
453
454                 if (*t == 127)
455                         return true;
456         }
457
458         return false;
459 }
460
461 static int write_ellipsis(char *buf, bool unicode) {
462         if (unicode || is_locale_utf8()) {
463                 buf[0] = 0xe2; /* tri-dot ellipsis: … */
464                 buf[1] = 0x80;
465                 buf[2] = 0xa6;
466         } else {
467                 buf[0] = '.';
468                 buf[1] = '.';
469                 buf[2] = '.';
470         }
471
472         return 3;
473 }
474
475 static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
476         size_t x, need_space;
477         char *r;
478
479         assert(s);
480         assert(percent <= 100);
481         assert(new_length != (size_t) -1);
482
483         if (old_length <= new_length)
484                 return strndup(s, old_length);
485
486         /* Special case short ellipsations */
487         switch (new_length) {
488
489         case 0:
490                 return strdup("");
491
492         case 1:
493                 if (is_locale_utf8())
494                         return strdup("…");
495                 else
496                         return strdup(".");
497
498         case 2:
499                 if (!is_locale_utf8())
500                         return strdup("..");
501
502                 break;
503
504         default:
505                 break;
506         }
507
508         /* Calculate how much space the ellipsis will take up. If we are in UTF-8 mode we only need space for one
509          * character ("…"), otherwise for three characters ("..."). Note that in both cases we need 3 bytes of storage,
510          * either for the UTF-8 encoded character or for three ASCII characters. */
511         need_space = is_locale_utf8() ? 1 : 3;
512
513         r = new(char, new_length+3);
514         if (!r)
515                 return NULL;
516
517         assert(new_length >= need_space);
518
519         x = ((new_length - need_space) * percent + 50) / 100;
520         assert(x <= new_length - need_space);
521
522         memcpy(r, s, x);
523         write_ellipsis(r + x, false);
524         memcpy(r + x + 3,
525                s + old_length - (new_length - x - need_space),
526                new_length - x - need_space + 1);
527
528         return r;
529 }
530
531 char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
532         size_t x, k, len, len2;
533         const char *i, *j;
534         char *e;
535         int r;
536
537         /* Note that 'old_length' refers to bytes in the string, while 'new_length' refers to character cells taken up
538          * on screen. This distinction doesn't matter for ASCII strings, but it does matter for non-ASCII UTF-8
539          * strings.
540          *
541          * Ellipsation is done in a locale-dependent way:
542          * 1. If the string passed in is fully ASCII and the current locale is not UTF-8, three dots are used ("...")
543          * 2. Otherwise, a unicode ellipsis is used ("…")
544          *
545          * In other words: you'll get a unicode ellipsis as soon as either the string contains non-ASCII characters or
546          * the current locale is UTF-8.
547          */
548
549         assert(s);
550         assert(percent <= 100);
551
552         if (new_length == (size_t) -1)
553                 return strndup(s, old_length);
554
555         if (new_length == 0)
556                 return strdup("");
557
558         /* If no multibyte characters use ascii_ellipsize_mem for speed */
559         if (ascii_is_valid(s))
560                 return ascii_ellipsize_mem(s, old_length, new_length, percent);
561
562         x = ((new_length - 1) * percent) / 100;
563         assert(x <= new_length - 1);
564
565         k = 0;
566         for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
567                 char32_t c;
568
569                 r = utf8_encoded_to_unichar(i, &c);
570                 if (r < 0)
571                         return NULL;
572                 k += unichar_iswide(c) ? 2 : 1;
573         }
574
575         if (k > x) /* last character was wide and went over quota */
576                 x++;
577
578         for (j = s + old_length; k < new_length && j > i; ) {
579                 char32_t c;
580
581                 j = utf8_prev_char(j);
582                 r = utf8_encoded_to_unichar(j, &c);
583                 if (r < 0)
584                         return NULL;
585                 k += unichar_iswide(c) ? 2 : 1;
586         }
587         assert(i <= j);
588
589         /* we don't actually need to ellipsize */
590         if (i == j)
591                 return memdup(s, old_length + 1);
592
593         /* make space for ellipsis */
594         j = utf8_next_char(j);
595
596         len = i - s;
597         len2 = s + old_length - j;
598         e = new(char, len + 3 + len2 + 1);
599         if (!e)
600                 return NULL;
601
602         /*
603         printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
604                old_length, new_length, x, len, len2, k);
605         */
606
607         memcpy(e, s, len);
608         write_ellipsis(e + len, true);
609         memcpy(e + len + 3, j, len2 + 1);
610
611         return e;
612 }
613
614 char *cellescape(char *buf, size_t len, const char *s) {
615         /* Escape and ellipsize s into buffer buf of size len. Only non-control ASCII
616          * characters are copied as they are, everything else is escaped. The result
617          * is different then if escaping and ellipsization was performed in two
618          * separate steps, because each sequence is either stored in full or skipped.
619          *
620          * This function should be used for logging about strings which expected to
621          * be plain ASCII in a safe way.
622          *
623          * An ellipsis will be used if s is too long. It was always placed at the
624          * very end.
625          */
626
627         size_t i = 0, last_char_width[4] = {}, k = 0, j;
628
629         assert(len > 0); /* at least a terminating NUL */
630
631         for (;;) {
632                 char four[4];
633                 int w;
634
635                 if (*s == 0) /* terminating NUL detected? then we are done! */
636                         goto done;
637
638                 w = cescape_char(*s, four);
639                 if (i + w + 1 > len) /* This character doesn't fit into the buffer anymore? In that case let's
640                                       * ellipsize at the previous location */
641                         break;
642
643                 /* OK, there was space, let's add this escaped character to the buffer */
644                 memcpy(buf + i, four, w);
645                 i += w;
646
647                 /* And remember its width in the ring buffer */
648                 last_char_width[k] = w;
649                 k = (k + 1) % 4;
650
651                 s++;
652         }
653
654         /* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4
655          * characters ideally, but the buffer is shorter than that in the first place take what we can get */
656         for (j = 0; j < ELEMENTSOF(last_char_width); j++) {
657
658                 if (i + 4 <= len) /* nice, we reached our space goal */
659                         break;
660
661                 k = k == 0 ? 3 : k - 1;
662                 if (last_char_width[k] == 0) /* bummer, we reached the beginning of the strings */
663                         break;
664
665                 assert(i >= last_char_width[k]);
666                 i -= last_char_width[k];
667         }
668
669         if (i + 4 <= len) /* yay, enough space */
670                 i += write_ellipsis(buf + i, false);
671         else if (i + 3 <= len) { /* only space for ".." */
672                 buf[i++] = '.';
673                 buf[i++] = '.';
674         } else if (i + 2 <= len) /* only space for a single "." */
675                 buf[i++] = '.';
676         else
677                 assert(i + 1 <= len);
678
679  done:
680         buf[i] = '\0';
681         return buf;
682 }
683
684 bool nulstr_contains(const char *nulstr, const char *needle) {
685         const char *i;
686
687         if (!nulstr)
688                 return false;
689
690         NULSTR_FOREACH(i, nulstr)
691                 if (streq(i, needle))
692                         return true;
693
694         return false;
695 }
696
697 char* strshorten(char *s, size_t l) {
698         assert(s);
699
700         if (strnlen(s, l+1) > l)
701                 s[l] = 0;
702
703         return s;
704 }
705
706 char *strreplace(const char *text, const char *old_string, const char *new_string) {
707         size_t l, old_len, new_len, allocated = 0;
708         char *t, *ret = NULL;
709         const char *f;
710
711         assert(old_string);
712         assert(new_string);
713
714         if (!text)
715                 return NULL;
716
717         old_len = strlen(old_string);
718         new_len = strlen(new_string);
719
720         l = strlen(text);
721         if (!GREEDY_REALLOC(ret, allocated, l+1))
722                 return NULL;
723
724         f = text;
725         t = ret;
726         while (*f) {
727                 size_t d, nl;
728
729                 if (!startswith(f, old_string)) {
730                         *(t++) = *(f++);
731                         continue;
732                 }
733
734                 d = t - ret;
735                 nl = l - old_len + new_len;
736
737                 if (!GREEDY_REALLOC(ret, allocated, nl + 1))
738                         return mfree(ret);
739
740                 l = nl;
741                 t = ret + d;
742
743                 t = stpcpy(t, new_string);
744                 f += old_len;
745         }
746
747         *t = 0;
748         return ret;
749 }
750
751 static void advance_offsets(ssize_t diff, size_t offsets[2], size_t shift[2], size_t size) {
752         if (!offsets)
753                 return;
754
755         if ((size_t) diff < offsets[0])
756                 shift[0] += size;
757         if ((size_t) diff < offsets[1])
758                 shift[1] += size;
759 }
760
761 char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
762         const char *i, *begin = NULL;
763         enum {
764                 STATE_OTHER,
765                 STATE_ESCAPE,
766                 STATE_CSI,
767                 STATE_CSO,
768         } state = STATE_OTHER;
769         char *obuf = NULL;
770         size_t osz = 0, isz, shift[2] = {};
771         FILE *f;
772
773         assert(ibuf);
774         assert(*ibuf);
775
776         /* This does three things:
777          *
778          * 1. Replaces TABs by 8 spaces
779          * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
780          * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences
781          *
782          * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as are any
783          * other special characters. Truncated ANSI sequences are left-as is too. This call is supposed to suppress the
784          * most basic formatting noise, but nothing else.
785          *
786          * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
787
788         isz = _isz ? *_isz : strlen(*ibuf);
789
790         f = open_memstream(&obuf, &osz);
791         if (!f)
792                 return NULL;
793
794         /* Note we turn off internal locking on f for performance reasons.  It's safe to do so since we created f here
795          * and it doesn't leave our scope. */
796
797         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
798
799         for (i = *ibuf; i < *ibuf + isz + 1; i++) {
800
801                 switch (state) {
802
803                 case STATE_OTHER:
804                         if (i >= *ibuf + isz) /* EOT */
805                                 break;
806                         else if (*i == '\x1B')
807                                 state = STATE_ESCAPE;
808                         else if (*i == '\t') {
809                                 fputs("        ", f);
810                                 advance_offsets(i - *ibuf, highlight, shift, 7);
811                         } else
812                                 fputc(*i, f);
813
814                         break;
815
816                 case STATE_ESCAPE:
817                         if (i >= *ibuf + isz) { /* EOT */
818                                 fputc('\x1B', f);
819                                 advance_offsets(i - *ibuf, highlight, shift, 1);
820                                 break;
821                         } else if (*i == '[') { /* ANSI CSI */
822                                 state = STATE_CSI;
823                                 begin = i + 1;
824                         } else if (*i == ']') { /* ANSI CSO */
825                                 state = STATE_CSO;
826                                 begin = i + 1;
827                         } else {
828                                 fputc('\x1B', f);
829                                 fputc(*i, f);
830                                 advance_offsets(i - *ibuf, highlight, shift, 1);
831                                 state = STATE_OTHER;
832                         }
833
834                         break;
835
836                 case STATE_CSI:
837
838                         if (i >= *ibuf + isz || /* EOT … */
839                             !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */
840                                 fputc('\x1B', f);
841                                 fputc('[', f);
842                                 advance_offsets(i - *ibuf, highlight, shift, 2);
843                                 state = STATE_OTHER;
844                                 i = begin-1;
845                         } else if (*i == 'm')
846                                 state = STATE_OTHER;
847
848                         break;
849
850                 case STATE_CSO:
851
852                         if (i >= *ibuf + isz || /* EOT … */
853                             (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
854                                 fputc('\x1B', f);
855                                 fputc(']', f);
856                                 advance_offsets(i - *ibuf, highlight, shift, 2);
857                                 state = STATE_OTHER;
858                                 i = begin-1;
859                         } else if (*i == '\a')
860                                 state = STATE_OTHER;
861
862                         break;
863                 }
864         }
865
866         if (fflush_and_check(f) < 0) {
867                 fclose(f);
868                 return mfree(obuf);
869         }
870
871         fclose(f);
872
873         free(*ibuf);
874         *ibuf = obuf;
875
876         if (_isz)
877                 *_isz = osz;
878
879         if (highlight) {
880                 highlight[0] += shift[0];
881                 highlight[1] += shift[1];
882         }
883
884         return obuf;
885 }
886
887 char *strextend_with_separator(char **x, const char *separator, ...) {
888         bool need_separator;
889         size_t f, l, l_separator;
890         char *r, *p;
891         va_list ap;
892
893         assert(x);
894
895         l = f = strlen_ptr(*x);
896
897         need_separator = !isempty(*x);
898         l_separator = strlen_ptr(separator);
899
900         va_start(ap, separator);
901         for (;;) {
902                 const char *t;
903                 size_t n;
904
905                 t = va_arg(ap, const char *);
906                 if (!t)
907                         break;
908
909                 n = strlen(t);
910
911                 if (need_separator)
912                         n += l_separator;
913
914                 if (n > ((size_t) -1) - l) {
915                         va_end(ap);
916                         return NULL;
917                 }
918
919                 l += n;
920                 need_separator = true;
921         }
922         va_end(ap);
923
924         need_separator = !isempty(*x);
925
926         r = realloc(*x, l+1);
927         if (!r)
928                 return NULL;
929
930         p = r + f;
931
932         va_start(ap, separator);
933         for (;;) {
934                 const char *t;
935
936                 t = va_arg(ap, const char *);
937                 if (!t)
938                         break;
939
940                 if (need_separator && separator)
941                         p = stpcpy(p, separator);
942
943                 p = stpcpy(p, t);
944
945                 need_separator = true;
946         }
947         va_end(ap);
948
949         assert(p == r + l);
950
951         *p = 0;
952         *x = r;
953
954         return r + l;
955 }
956
957 char *strrep(const char *s, unsigned n) {
958         size_t l;
959         char *r, *p;
960         unsigned i;
961
962         assert(s);
963
964         l = strlen(s);
965         p = r = malloc(l * n + 1);
966         if (!r)
967                 return NULL;
968
969         for (i = 0; i < n; i++)
970                 p = stpcpy(p, s);
971
972         *p = 0;
973         return r;
974 }
975
976 int split_pair(const char *s, const char *sep, char **l, char **r) {
977         char *x, *a, *b;
978
979         assert(s);
980         assert(sep);
981         assert(l);
982         assert(r);
983
984         if (isempty(sep))
985                 return -EINVAL;
986
987         x = strstr(s, sep);
988         if (!x)
989                 return -EINVAL;
990
991         a = strndup(s, x - s);
992         if (!a)
993                 return -ENOMEM;
994
995         b = strdup(x + strlen(sep));
996         if (!b) {
997                 free(a);
998                 return -ENOMEM;
999         }
1000
1001         *l = a;
1002         *r = b;
1003
1004         return 0;
1005 }
1006
1007 int free_and_strdup(char **p, const char *s) {
1008         char *t;
1009
1010         assert(p);
1011
1012         /* Replaces a string pointer with an strdup()ed new string,
1013          * possibly freeing the old one. */
1014
1015         if (streq_ptr(*p, s))
1016                 return 0;
1017
1018         if (s) {
1019                 t = strdup(s);
1020                 if (!t)
1021                         return -ENOMEM;
1022         } else
1023                 t = NULL;
1024
1025         free(*p);
1026         *p = t;
1027
1028         return 1;
1029 }
1030
1031 #if !HAVE_EXPLICIT_BZERO
1032 /*
1033  * Pointer to memset is volatile so that compiler must de-reference
1034  * the pointer and can't assume that it points to any function in
1035  * particular (such as memset, which it then might further "optimize")
1036  * This approach is inspired by openssl's crypto/mem_clr.c.
1037  */
1038 typedef void *(*memset_t)(void *,int,size_t);
1039
1040 static volatile memset_t memset_func = memset;
1041
1042 void explicit_bzero(void *p, size_t l) {
1043         memset_func(p, '\0', l);
1044 }
1045 #endif
1046
1047 char* string_erase(char *x) {
1048         if (!x)
1049                 return NULL;
1050
1051         /* A delicious drop of snake-oil! To be called on memory where
1052          * we stored passphrases or so, after we used them. */
1053         explicit_bzero(x, strlen(x));
1054         return x;
1055 }
1056
1057 char *string_free_erase(char *s) {
1058         return mfree(string_erase(s));
1059 }
1060
1061 bool string_is_safe(const char *p) {
1062         const char *t;
1063
1064         if (!p)
1065                 return false;
1066
1067         for (t = p; *t; t++) {
1068                 if (*t > 0 && *t < ' ') /* no control characters */
1069                         return false;
1070
1071                 if (strchr(QUOTES "\\\x7f", *t))
1072                         return false;
1073         }
1074
1075         return true;
1076 }