diff --git a/CHANGELOG.md b/CHANGELOG.md index eedc5f6..3c13106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ ## Unreleased ### Added + +* environment variable substitution in config files ([#388][388]). + +[388]: https://codeberg.org/dnkl/yambar/issues/388 + ### Changed * `river`: expand to an empty list of particles when river is not diff --git a/doc/yambar.5.scd b/doc/yambar.5.scd index 1b06939..cc03f8c 100644 --- a/doc/yambar.5.scd +++ b/doc/yambar.5.scd @@ -23,6 +23,11 @@ types that are frequently used: - 000000ff: black, no transparency - 00ff00ff: green, no transparency - ff000099: red, semi-transparent +- *environment reference*: a string that contains format ${VAR}. This will be + replaced by the value of the environment variable VAR. Example: + - ${HOME} + - ${HOME}/.config/yambar + - ENV is ${ENV}, ENV2 is ${ENV2} # FORMAT [[ *Name* diff --git a/yml.c b/yml.c index ec08101..73dba66 100644 --- a/yml.c +++ b/yml.c @@ -366,6 +366,44 @@ format_error(enum yml_error err, const struct yml_node *parent, const struct yml return err_str; } +static char * +replace_env_variables(const char *str, size_t len) +{ + char *result = strndup(str, len); + char *start, *end, *key, *env_value; + char* prefix = "${"; + char* suffix = "}"; + size_t pref_len = 2; + size_t suff_len = 1; + size_t key_len; + + while ((start = strstr(result, prefix)) && (end = strstr(start, suffix))) { + key_len = end - start - pref_len; + key = strndup(start + pref_len, key_len); + env_value = getenv(key); + + if (env_value) { + size_t result_len = strlen(result); + size_t new_len = result_len - key_len - pref_len - suff_len + strlen(env_value); + char *new_result = malloc(new_len + 1); + + strncpy(new_result, result, start - result); + new_result[start - result] = '\0'; + strcat(new_result, env_value); + strcat(new_result, end + 1); + + free(result); + result = new_result; + } else { + memmove(start, end + 1, strlen(end + 1) + 1); + } + + free(key); + } + + return result; +} + struct yml_node * yml_load(FILE *yml, char **error) { @@ -456,7 +494,7 @@ yml_load(FILE *yml, char **error) case YAML_SCALAR_EVENT: { struct yml_node *new_scalar = calloc(1, sizeof(*new_scalar)); new_scalar->type = SCALAR; - new_scalar->scalar.value = strndup((const char *)event.data.scalar.value, event.data.scalar.length); + new_scalar->scalar.value = replace_env_variables((const char *)event.data.scalar.value, event.data.scalar.length); enum yml_error err = add_node(n, new_scalar, event.start_mark); if (err != YML_ERR_NONE) {