]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/replace-var.c
tree-wide: drop string.h when string-util.h or friends are included
[thirdparty/systemd.git] / src / basic / replace-var.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6e6fb527 2
11c3a366
TA
3#include <errno.h>
4#include <stddef.h>
5#include <stdlib.h>
6e6fb527 6
b5efdb8a 7#include "alloc-util.h"
6e6fb527 8#include "macro.h"
6e6fb527 9#include "replace-var.h"
b11d6a7b 10#include "string-util.h"
6e6fb527
LP
11
12/*
13 * Generic infrastructure for replacing @FOO@ style variables in
14 * strings. Will call a callback for each replacement.
15 */
16
17static int get_variable(const char *b, char **r) {
18 size_t k;
19 char *t;
20
21 assert(b);
22 assert(r);
23
24 if (*b != '@')
25 return 0;
26
4b549144 27 k = strspn(b + 1, UPPERCASE_LETTERS "_");
6e6fb527
LP
28 if (k <= 0 || b[k+1] != '@')
29 return 0;
30
31 t = strndup(b + 1, k);
32 if (!t)
33 return -ENOMEM;
34
35 *r = t;
36 return 1;
37}
38
2d5dece8 39char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata) {
6e6fb527
LP
40 char *r, *t;
41 const char *f;
42 size_t l;
43
44 assert(text);
45 assert(lookup);
46
47 l = strlen(text);
48 r = new(char, l+1);
49 if (!r)
50 return NULL;
51
52 f = text;
53 t = r;
54 while (*f) {
55 _cleanup_free_ char *v = NULL, *n = NULL;
56 char *a;
57 int k;
58 size_t skip, d, nl;
59
60 k = get_variable(f, &v);
61 if (k < 0)
62 goto oom;
63 if (k == 0) {
64 *(t++) = *(f++);
65 continue;
66 }
67
68 n = lookup(v, userdata);
69 if (!n)
70 goto oom;
71
72 skip = strlen(v) + 2;
73
74 d = t - r;
75 nl = l - skip + strlen(n);
76 a = realloc(r, nl + 1);
77 if (!a)
78 goto oom;
79
80 l = nl;
81 r = a;
82 t = r + d;
83
84 t = stpcpy(t, n);
85 f += skip;
86 }
87
88 *t = 0;
89 return r;
90
91oom:
6b430fdb 92 return mfree(r);
6e6fb527 93}