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