diff options
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/env-util.c | 67 | ||||
-rw-r--r-- | src/basic/env-util.h | 1 | ||||
-rw-r--r-- | src/basic/fileio.c | 6 |
3 files changed, 69 insertions, 5 deletions
diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 1b955ff1d5..2ca64c3301 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -525,12 +525,16 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { CURLY, VARIABLE, VARIABLE_RAW, + TEST, + DEFAULT_VALUE, + ALTERNATE_VALUE, } state = WORD; - const char *e, *word = format; + const char *e, *word = format, *test_value; char *k; _cleanup_free_ char *r = NULL; - size_t i; + size_t i, len; + int nest = 0; assert(format); @@ -554,7 +558,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { word = e-1; state = VARIABLE; - + nest++; } else if (*e == '$') { k = strnappend(r, word, e-word); if (!k) @@ -596,6 +600,63 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { word = e+1; state = WORD; + } else if (*e == ':') { + if (!(flags & REPLACE_ENV_ALLOW_EXTENDED)) + /* Treat this as unsupported syntax, i.e. do no replacement */ + state = WORD; + else { + len = e-word-2; + state = TEST; + } + } + break; + + case TEST: + if (*e == '-') + state = DEFAULT_VALUE; + else if (*e == '+') + state = ALTERNATE_VALUE; + else { + state = WORD; + break; + } + + test_value = e+1; + break; + + case DEFAULT_VALUE: /* fall through */ + case ALTERNATE_VALUE: + assert(flags & REPLACE_ENV_ALLOW_EXTENDED); + + if (*e == '{') { + nest++; + break; + } + + if (*e != '}') + break; + + nest--; + if (nest == 0) { // || !strchr(e+1, '}')) { + const char *t; + _cleanup_free_ char *v = NULL; + + t = strv_env_get_n(env, word+2, len, flags); + + if (t && state == ALTERNATE_VALUE) + t = v = replace_env_n(test_value, e-test_value, env, flags); + else if (!t && state == DEFAULT_VALUE) + t = v = replace_env_n(test_value, e-test_value, env, flags); + + k = strappend(r, t); + if (!k) + return NULL; + + free(r); + r = k; + + word = e+1; + state = WORD; } break; diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 43a1371f5e..e88fa6aac0 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -32,6 +32,7 @@ bool env_assignment_is_valid(const char *e); enum { REPLACE_ENV_USE_ENVIRONMENT = 1u, REPLACE_ENV_ALLOW_BRACELESS = 2u, + REPLACE_ENV_ALLOW_EXTENDED = 4u, }; char *replace_env_n(const char *format, size_t n, char **env, unsigned flags); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 8185f67e00..b9a9f74892 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -784,7 +784,9 @@ static int merge_env_file_push( } expanded_value = replace_env(value, *env, - REPLACE_ENV_USE_ENVIRONMENT|REPLACE_ENV_ALLOW_BRACELESS); + REPLACE_ENV_USE_ENVIRONMENT| + REPLACE_ENV_ALLOW_BRACELESS| + REPLACE_ENV_ALLOW_EXTENDED); if (!expanded_value) return -ENOMEM; @@ -799,7 +801,7 @@ int merge_env_file( const char *fname) { /* NOTE: this function supports braceful and braceless variable expansions, - * unlike other exported parsing functions. + * plus "extended" substitutions, unlike other exported parsing functions. */ return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL); |