diff options
Diffstat (limited to 'src/shared/env-util.c')
-rw-r--r-- | src/shared/env-util.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/shared/env-util.c b/src/shared/env-util.c index 00c2cdd8c4..ac7bbdc711 100644 --- a/src/shared/env-util.c +++ b/src/shared/env-util.c @@ -448,3 +448,147 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha return e; } + +char *replace_env(const char *format, char **env) { + enum { + WORD, + CURLY, + VARIABLE + } state = WORD; + + const char *e, *word = format; + char *r = NULL, *k; + + assert(format); + + for (e = format; *e; e ++) { + + switch (state) { + + case WORD: + if (*e == '$') + state = CURLY; + break; + + case CURLY: + if (*e == '{') { + k = strnappend(r, word, e-word-1); + if (!k) + goto fail; + + free(r); + r = k; + + word = e-1; + state = VARIABLE; + + } else if (*e == '$') { + k = strnappend(r, word, e-word); + if (!k) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } else + state = WORD; + break; + + case VARIABLE: + if (*e == '}') { + const char *t; + + t = strempty(strv_env_get_n(env, word+2, e-word-2)); + + k = strappend(r, t); + if (!k) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } + break; + } + } + + k = strnappend(r, word, e-word); + if (!k) + goto fail; + + free(r); + return k; + +fail: + free(r); + return NULL; +} + +char **replace_env_argv(char **argv, char **env) { + char **ret, **i; + unsigned k = 0, l = 0; + + l = strv_length(argv); + + ret = new(char*, l+1); + if (!ret) + return NULL; + + STRV_FOREACH(i, argv) { + + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$' && (*i)[1] != '{') { + char *e; + char **w, **m = NULL; + unsigned q; + + e = strv_env_get(env, *i+1); + if (e) { + int r; + + r = strv_split_quoted(&m, e, UNQUOTE_RELAX); + if (r < 0) { + ret[k] = NULL; + strv_free(ret); + return NULL; + } + } else + m = NULL; + + q = strv_length(m); + l = l + q - 1; + + w = realloc(ret, sizeof(char*) * (l+1)); + if (!w) { + ret[k] = NULL; + strv_free(ret); + strv_free(m); + return NULL; + } + + ret = w; + if (m) { + memcpy(ret + k, m, q * sizeof(char*)); + free(m); + } + + k += q; + continue; + } + + /* If ${FOO} appears as part of a word, replace it by the variable as-is */ + ret[k] = replace_env(*i, env); + if (!ret[k]) { + strv_free(ret); + return NULL; + } + k++; + } + + ret[k] = NULL; + return ret; +} |