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