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