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