From: Lennart Poettering Date: Wed, 14 Nov 2012 21:20:17 +0000 (+0100) Subject: shared: add API for replacing @FOO@ style variables in strings X-Git-Tag: v196~84 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=6e6fb527f987d0c1f5bd930020301c9ac76a5e2c shared: add API for replacing @FOO@ style variables in strings --- diff --git a/.gitignore b/.gitignore index 94a85423a..18e4e23c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/test-replace-var /test-journal-enum /test-sleep /localectl diff --git a/Makefile.am b/Makefile.am index 452de152d..53a3bb9f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -798,6 +798,8 @@ libsystemd_shared_la_SOURCES = \ src/shared/spawn-ask-password-agent.h \ src/shared/specifier.c \ src/shared/specifier.h \ + src/shared/replace-var.c \ + src/shared/replace-var.h \ src/shared/spawn-polkit-agent.c \ src/shared/spawn-polkit-agent.h \ src/shared/hwclock.c \ @@ -1182,7 +1184,8 @@ noinst_PROGRAMS += \ test-log \ test-unit-file \ test-date \ - test-sleep + test-sleep \ + test-replace-var TESTS += \ test-job-type \ @@ -1191,7 +1194,8 @@ TESTS += \ test-unit-name \ test-unit-file \ test-date \ - test-sleep + test-sleep \ + test-replace-var test_engine_SOURCES = \ src/test/test-engine.c @@ -1265,6 +1269,12 @@ test_sleep_SOURCES = \ test_sleep_LDADD = \ libsystemd-core.la +test_replace_var_SOURCES = \ + src/test/test-replace-var.c + +test_replace_var_LDADD = \ + libsystemd-shared.la + test_daemon_SOURCES = \ src/test/test-daemon.c diff --git a/src/shared/replace-var.c b/src/shared/replace-var.c new file mode 100644 index 000000000..e11c57a43 --- /dev/null +++ b/src/shared/replace-var.c @@ -0,0 +1,110 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" +#include "util.h" +#include "replace-var.h" + +/* + * Generic infrastructure for replacing @FOO@ style variables in + * strings. Will call a callback for each replacement. + */ + +static int get_variable(const char *b, char **r) { + size_t k; + char *t; + + assert(b); + assert(r); + + if (*b != '@') + return 0; + + k = strspn(b + 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); + if (k <= 0 || b[k+1] != '@') + return 0; + + t = strndup(b + 1, k); + if (!t) + return -ENOMEM; + + *r = t; + return 1; +} + +char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata) { + char *r, *t; + const char *f; + size_t l; + + assert(text); + assert(lookup); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + _cleanup_free_ char *v = NULL, *n = NULL; + char *a; + int k; + size_t skip, d, nl; + + k = get_variable(f, &v); + if (k < 0) + goto oom; + if (k == 0) { + *(t++) = *(f++); + continue; + } + + n = lookup(v, userdata); + if (!n) + goto oom; + + skip = strlen(v) + 2; + + d = t - r; + nl = l - skip + strlen(n); + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, n); + f += skip; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} diff --git a/src/shared/replace-var.h b/src/shared/replace-var.h new file mode 100644 index 000000000..7eaee93a3 --- /dev/null +++ b/src/shared/replace-var.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata); diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c new file mode 100644 index 000000000..b1d42d77f --- /dev/null +++ b/src/test/test-replace-var.c @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "macro.h" +#include "replace-var.h" + +static char *lookup(const char *variable, void *userdata) { + return strjoin("<<<", variable, ">>>", NULL); +} + +int main(int argc, char *argv[]) { + char *r; + + assert_se(r = replace_var("@@@foobar@xyz@HALLO@foobar@test@@testtest@TEST@...@@@", lookup, NULL)); + puts(r); + assert_se(streq(r, "@@@foobar@xyz<<>>foobar@test@@testtest<<>>...@@@")); + free(r); + + assert_se(r = strreplace("XYZFFFFXYZFFFFXYZ", "XYZ", "ABC")); + puts(r); + assert_se(streq(r, "ABCFFFFABCFFFFABC")); + free(r); + + return 0; +}