From bd699985169ecf44cd957e3832077c79b180760e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 28 Jun 2019 13:35:55 +1000 Subject: [PATCH] mconf-idf: Use same 'simple expand' logic, same as kconfig-frontends Previously, wordexp() was used. However for providing Windows builds of mconf-idf we can't use wordexp() so we use this simplified environment variable expansion code instead. The reasoning here is to make the behaviour consistent across Windows (CMake vs GNU Make), Linux & macOS mconf. --- tools/kconfig/Makefile | 12 +++--- tools/kconfig/expand_env.c | 88 ++++++++++++++++++++++++++++++++++++++ tools/kconfig/expand_env.h | 13 ++++++ tools/kconfig/zconf.l | 34 ++++++++++----- 4 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 tools/kconfig/expand_env.c create mode 100644 tools/kconfig/expand_env.h 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)