1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <stddef.h>
5 #include <stdlib.h>
6 
7 #include "alloc-util.h"
8 #include "macro.h"
9 #include "replace-var.h"
10 #include "string-util.h"
11 
12 /*
13  * Generic infrastructure for replacing @FOO@ style variables in
14  * strings. Will call a callback for each replacement.
15  */
16 
get_variable(const char * b,char ** r)17 static 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 
27         k = strspn(b + 1, UPPERCASE_LETTERS "_");
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 
replace_var(const char * text,char * (* lookup)(const char * variable,void * userdata),void * userdata)39 char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata) {
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 
91 oom:
92         return mfree(r);
93 }
94