diff --git a/tools/kconfig/Makefile b/tools/kconfig/Makefile index 106ffb6b4..c9488d8cd 100644 --- a/tools/kconfig/Makefile +++ b/tools/kconfig/Makefile @@ -192,13 +192,13 @@ lxdialog/%.o: $(SRCDIR)/lxdialog/%.c lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o -conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) -nconf-objs := nconf.o zconf.tab.o nconf.gui.o -kxgettext-objs := kxgettext.o zconf.tab.o +conf-objs := conf.o zconf.tab.o expand_env.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) expand_env.o +nconf-objs := nconf.o zconf.tab.o nconf.gui.o expand_env.o +kxgettext-objs := kxgettext.o zconf.tab.o expand_env.o qconf-cxxobjs := qconf.o -qconf-objs := zconf.tab.o -gconf-objs := gconf.o zconf.tab.o +qconf-objs := zconf.tab.o expand_env.o +gconf-objs := gconf.o zconf.tab.o expand_env.o hostprogs-y := conf-idf nconf mconf-idf kxgettext qconf gconf diff --git a/tools/kconfig/expand_env.c b/tools/kconfig/expand_env.c new file mode 100644 index 000000000..185280e00 --- /dev/null +++ b/tools/kconfig/expand_env.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +#include "expand_env.h" + +static bool allowed_env_var_name(char c) +{ + return c != '\0' && + !isblank(c) && + !iscntrl(c) && + c != '/' && + c != '\\' && + c != '=' && + c != '$'; +} + +#define MAX_LEN (128 * 1024) /* Longest a result can expand to */ + +/* Very basic expansion that looks for variable references like $NAME and expands them + * + */ +char *expand_environment(const char *input, const char *src_name, int src_line_no) +{ + char *result = malloc(MAX_LEN); + + char *out = result; + const char *in = input; + + while (*in != '\0') { + // check for buffer overflow + if (out >= result + MAX_LEN - 1) { + goto too_long; + } + + if (*in != '$') { + // not part of an environment variable name, copy directly + *out++ = *in++; + continue; + } + + // *in points to start of an environment variable reference + in++; + const char *env_start = in; + while (allowed_env_var_name(*in)) { // scan to the end of the name + in++; + } + size_t env_len = in - env_start; + + // make a buffer to hold the environment variable name + // + // strndup is not available on mingw32, apparently. + char *env_name = calloc(1, env_len + 1); + assert(env_name != NULL); + strncpy(env_name, env_start, env_len); + + const char *value = getenv(env_name); + if (value == NULL || strlen(value) == 0) { + printf("%s:%d: undefined environment variable \"%s\"\n", + src_name, src_line_no, env_name); + exit(1); + } + free(env_name); + if (out + strlen(value) >= result + MAX_LEN - 1) { + goto too_long; + } + strcpy(out, value); // append the value to the result (range checked in previous statement) + out += strlen(value); + } + + *out = '\0'; // null terminate the result string + + return result; + +too_long: + printf("%s:%d: Expansion is longer than %d bytes\n", + src_name, src_line_no, MAX_LEN); + free(result); + exit(1); +} + +void free_expanded(char *expanded) +{ + free(expanded); +} diff --git a/tools/kconfig/expand_env.h b/tools/kconfig/expand_env.h new file mode 100644 index 000000000..4404523af --- /dev/null +++ b/tools/kconfig/expand_env.h @@ -0,0 +1,13 @@ +#pragma once + +/* Expand any $ENV type environment variables in 'input', + return a newly allocated buffer with the result. + + Buffer should be freed after use. + + This is very basic expansion, doesn't do escaping or anything else. +*/ +char *expand_environment(const char *input, const char *src_name, int src_line_no); + +/* Free a buffer allocated by expand_environment */ +void free_expanded(char *expanded); diff --git a/tools/kconfig/zconf.l b/tools/kconfig/zconf.l index fa0da6b70..b8cc8939a 100644 --- a/tools/kconfig/zconf.l +++ b/tools/kconfig/zconf.l @@ -13,9 +13,9 @@ #include #include #include -#include #include "lkc.h" +#include "expand_env.h" #define START_STRSIZE 16 @@ -348,19 +348,33 @@ void zconf_nextfile(const char *name) current_file = file; } -void zconf_nextfiles(const char *wildcard) +void zconf_nextfiles(const char *expression) { - wordexp_t p; - char **w; - int i; + /* Expand environment variables in 'expression' */ + char* str = expand_environment(expression, zconf_curname(), zconf_lineno()); - wordexp(wildcard, &p, 0); - w = p.we_wordv; + /* zconf_nextfile() processes files in LIFO order, so to keep the + files in the order provided we need to process the list backwards + */ + if (str != NULL && strlen(str)) { + char* pos = str + strlen(str); // start at null terminator - for (i = p.we_wordc - 1; i >= 0; i--) - zconf_nextfile(w[i]); + while (pos != str) { + pos--; + if(*pos == ' ') { + *pos = '\0'; // split buffer into multiple c-strings + if (strlen(pos + 1)) { + zconf_nextfile(pos + 1); + } + } + } - wordfree(&p); + if (strlen(str)) { // re-check as first character may have been a space + zconf_nextfile(str); + } + } + + free_expanded(str); } static void zconf_endfile(void)