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