From c164bf7f87f9081fee7e1a186dd7a87a9a020b9e Mon Sep 17 00:00:00 2001 From: Jason Self Date: Thu, 4 Jul 2019 15:12:33 -0700 Subject: [PATCH] Update carl9170 to latest upstream Based on commit 001384147050b9cd9daadb4d3115cc0f13f5b319 Dated May 5 2019. --- WHENCE | 4 +- carl9170fw/carlfw/include/wl.h | 2 +- carl9170fw/carlfw/src/hostif.c | 8 +- carl9170fw/carlfw/src/printf.c | 0 carl9170fw/carlfw/src/wlantx.c | 5 +- carl9170fw/config/CMakeLists.txt | 6 +- carl9170fw/config/conf.c | 210 ++++++---- carl9170fw/config/confdata.c | 329 +++++++++------ carl9170fw/config/expr.c | 206 +++++++--- carl9170fw/config/expr.h | 105 ++++- carl9170fw/config/kconf_id.c | 54 --- carl9170fw/config/lkc.h | 50 +-- carl9170fw/config/lkc_proto.h | 19 +- carl9170fw/config/menu.c | 259 +++++++++--- carl9170fw/config/preprocess.c | 573 +++++++++++++++++++++++++++ carl9170fw/config/symbol.c | 255 ++++-------- carl9170fw/config/util.c | 86 ++-- carl9170fw/config/zconf.l | 336 ++++++++++------ carl9170fw/config/zconf.y | 403 +++++++++---------- carl9170fw/include/linux/ieee80211.h | 24 +- carl9170fw/include/shared/wlan.h | 2 +- carl9170fw/toolchain/Makefile | 8 +- carl9170fw/toolchain/SHA256SUMS | 18 +- 23 files changed, 1942 insertions(+), 1020 deletions(-) mode change 100755 => 100644 carl9170fw/carlfw/src/printf.c delete mode 100644 carl9170fw/config/kconf_id.c create mode 100644 carl9170fw/config/preprocess.c diff --git a/WHENCE b/WHENCE index dd8ec20..2932155 100644 --- a/WHENCE +++ b/WHENCE @@ -142,8 +142,8 @@ From https://git.kernel.org/pub/scm/utils/cis-tools/cis-tools.git Driver: carl9170 -- Atheros AR9170 802.11 draft-n USB driver -Version: Based on commit 370b7919114a02149088c482c8709cafb9bf7478 -dated May 2 2018. +Version: Based on commit 001384147050b9cd9daadb4d3115cc0f13f5b319 +dated May 5 2019. Licence: GPLv2 or later. diff --git a/carl9170fw/carlfw/include/wl.h b/carl9170fw/carlfw/include/wl.h index 8499ca2..5566be4 100644 --- a/carl9170fw/carlfw/include/wl.h +++ b/carl9170fw/carlfw/include/wl.h @@ -237,7 +237,7 @@ static inline __inline void unhide_super(struct dma_desc *desc) desc->totalLen += sizeof(struct carl9170_tx_superdesc); } -static inline __inline __hot void read_tsf(uint32_t *tsf) +static inline __inline __hot void read_tsf(uint32_t tsf[static 2]) { /* * "According to the [hardware] documentation: diff --git a/carl9170fw/carlfw/src/hostif.c b/carl9170fw/carlfw/src/hostif.c index 73e89c7..06726db 100644 --- a/carl9170fw/carlfw/src/hostif.c +++ b/carl9170fw/carlfw/src/hostif.c @@ -213,10 +213,14 @@ void handle_cmd(struct carl9170_rsp *resp) fw.reboot = 1; break; - case CARL9170_CMD_READ_TSF: + case CARL9170_CMD_READ_TSF: { + uint32_t tmptsf[2]; + + read_tsf(tmptsf); resp->hdr.len = 8; - read_tsf((uint32_t *)resp->tsf.tsf); + memcpy(resp->tsf.tsf, tmptsf, sizeof(tmptsf)); break; + } case CARL9170_CMD_RX_FILTER: resp->hdr.len = 0; diff --git a/carl9170fw/carlfw/src/printf.c b/carl9170fw/carlfw/src/printf.c old mode 100755 new mode 100644 diff --git a/carl9170fw/carlfw/src/wlantx.c b/carl9170fw/carlfw/src/wlantx.c index 474c040..a8d0952 100644 --- a/carl9170fw/carlfw/src/wlantx.c +++ b/carl9170fw/carlfw/src/wlantx.c @@ -260,7 +260,7 @@ static void __wlan_tx(struct dma_desc *desc) if (unlikely(super->s.fill_in_tsf)) { struct ieee80211_mgmt *mgmt = (void *) &super->f.data.i3e; - uint32_t *tsf = (uint32_t *) &mgmt->u.probe_resp.timestamp; + uint32_t tmptsf[2]; /* * Truth be told: this is a hack. @@ -272,7 +272,8 @@ static void __wlan_tx(struct dma_desc *desc) * (even, if it's got an accurate atomic clock source). */ - read_tsf(tsf); + read_tsf(tmptsf); + memcpy(&mgmt->u.probe_resp.timestamp, tmptsf, sizeof(tmptsf)); } wlan_tx_ampdu(super); diff --git a/carl9170fw/config/CMakeLists.txt b/carl9170fw/config/CMakeLists.txt index 0a96a82..23e7218 100644 --- a/carl9170fw/config/CMakeLists.txt +++ b/carl9170fw/config/CMakeLists.txt @@ -11,13 +11,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../include/generated") -BISON_TARGET(zconf zconf.y zconf.tab.c COMPILE_FLAGS "-l -b zconf -p zconf -t") -FLEX_TARGET(zconfscan zconf.l zconf.lex.c COMPILE_FLAGS "-Pzconf -L") +BISON_TARGET(zconf zconf.y zconf.tab.c COMPILE_FLAGS "-l -b zconf -p yy -t") +FLEX_TARGET(zconfscan zconf.l zconf.lex.c COMPILE_FLAGS "-Pyy -L") SET(zconf_deps ${FLEX_zconfscan_OUTPUTS}) SET_SOURCE_FILES_PROPERTIES(${BISON_zconf_OUTPUTS} PROPERTIES OBJECT_DEPENDS "${zconf_deps}") -set(conf_src conf.c ${BISON_zconf_OUTPUTS}) +set(conf_src conf.c symbol.c confdata.c expr.c preprocess.c ${BISON_zconf_OUTPUTS} ${FLEX_zconfscan_OUTPUTS}) add_executable(conf ${conf_src}) diff --git a/carl9170fw/config/conf.c b/carl9170fw/config/conf.c index 6be6143..2949b7d 100644 --- a/carl9170fw/config/conf.c +++ b/carl9170fw/config/conf.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ -#include #include #include #include @@ -20,10 +19,10 @@ static void conf(struct menu *menu); static void check_conf(struct menu *menu); -static void xfgets(char *str, int size, FILE *in); enum input_mode { oldaskconfig, + syncconfig, oldconfig, allnoconfig, allyesconfig, @@ -33,12 +32,13 @@ enum input_mode { defconfig, savedefconfig, listnewconfig, - oldnoconfig, -} input_mode = oldaskconfig; + olddefconfig, +}; +static enum input_mode input_mode = oldaskconfig; static int indent = 1; static int tty_stdio; -static int valid_stdin = 1; +static int sync_kconfig; static int conf_cnt; static char line[PATH_MAX]; static struct menu *rootEntry; @@ -70,14 +70,14 @@ static void strip(char *str) *p-- = 0; } -static void check_stdin(void) +/* Helper function to facilitate fgets() by Jean Sacren. */ +static void xfgets(char *str, int size, FILE *in) { - if (!valid_stdin) { - printf(_("aborted!\n\n")); - printf(_("Console input/output is redirected. ")); - printf(_("Run 'make config' to update configuration.\n\n")); - exit(1); - } + if (!fgets(str, size, in)) + fprintf(stderr, "\nError in reading or end of file.\n"); + + if (!tty_stdio) + printf("%s", str); } static int conf_askvalue(struct symbol *sym, const char *def) @@ -85,7 +85,7 @@ static int conf_askvalue(struct symbol *sym, const char *def) enum symbol_type type = sym_get_type(sym); if (!sym_has_value(sym)) - printf(_("(NEW) ")); + printf("(NEW) "); line[0] = '\n'; line[1] = 0; @@ -99,17 +99,15 @@ static int conf_askvalue(struct symbol *sym, const char *def) switch (input_mode) { case oldconfig: + case syncconfig: if (sym_has_value(sym)) { printf("%s\n", def); return 0; } - check_stdin(); /* fall through */ case oldaskconfig: fflush(stdout); xfgets(line, sizeof(line), stdin); - if (!tty_stdio) - printf("\n"); return 1; default: break; @@ -134,7 +132,7 @@ static int conf_string(struct menu *menu) const char *def; while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("%*s%s ", indent - 1, "", menu->prompt->text); printf("(%s) ", sym->name); def = sym_get_string_value(sym); if (sym_get_string_value(sym)) @@ -167,7 +165,7 @@ static int conf_sym(struct menu *menu) tristate oldval, newval; while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("%*s%s ", indent - 1, "", menu->prompt->text); if (sym->name) printf("(%s) ", sym->name); putchar('['); @@ -189,9 +187,7 @@ static int conf_sym(struct menu *menu) printf("/m"); if (oldval != yes && sym_tristate_within_range(sym, yes)) printf("/y"); - if (menu_has_help(menu)) - printf("/?"); - printf("] "); + printf("/?] "); if (!conf_askvalue(sym, sym_get_string_value(sym))) return 0; strip(line); @@ -254,7 +250,7 @@ static int conf_choice(struct menu *menu) case no: return 1; case mod: - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); return 0; case yes: break; @@ -264,7 +260,7 @@ static int conf_choice(struct menu *menu) while (1) { int cnt, def; - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); def_sym = sym_get_choice_value(sym); cnt = def = 0; line[0] = 0; @@ -272,7 +268,7 @@ static int conf_choice(struct menu *menu) if (!menu_is_visible(child)) continue; if (!child->sym) { - printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + printf("%*c %s\n", indent, '*', menu_get_prompt(child)); continue; } cnt++; @@ -281,30 +277,27 @@ static int conf_choice(struct menu *menu) printf("%*c", indent, '>'); } else printf("%*c", indent, ' '); - printf(" %d. %s", cnt, _(menu_get_prompt(child))); + printf(" %d. %s", cnt, menu_get_prompt(child)); if (child->sym->name) printf(" (%s)", child->sym->name); if (!sym_has_value(child->sym)) - printf(_(" (NEW)")); + printf(" (NEW)"); printf("\n"); } - printf(_("%*schoice"), indent - 1, ""); + printf("%*schoice", indent - 1, ""); if (cnt == 1) { printf("[1]: 1\n"); goto conf_childs; } - printf("[1-%d", cnt); - if (menu_has_help(menu)) - printf("?"); - printf("]: "); + printf("[1-%d?]: ", cnt); switch (input_mode) { case oldconfig: + case syncconfig: if (!is_new) { cnt = def; printf("%d\n", cnt); break; } - check_stdin(); /* fall through */ case oldaskconfig: fflush(stdout); @@ -364,9 +357,11 @@ static void conf(struct menu *menu) switch (prop->type) { case P_MENU: - if ((input_mode == listnewconfig || - input_mode == oldnoconfig) && - rootEntry != menu) { + /* + * Except in oldaskconfig mode, we show only menus that + * contain new symbols. + */ + if (input_mode != oldaskconfig && rootEntry != menu) { check_conf(menu); return; } @@ -376,7 +371,7 @@ static void conf(struct menu *menu) if (prompt) printf("%*c\n%*c %s\n%*c\n", indent, '*', - indent, '*', _(prompt), + indent, '*', prompt, indent, '*'); default: ; @@ -426,12 +421,22 @@ static void check_conf(struct menu *menu) if (sym_is_changable(sym) || (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { if (input_mode == listnewconfig) { - if (sym->name && !sym_is_choice_value(sym)) { - printf("%s%s\n", CONFIG_, sym->name); + if (sym->name) { + const char *str; + + if (sym->type == S_STRING) { + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printf("%s%s=%s\n", CONFIG_, sym->name, str); + free((void *)str); + } else { + str = sym_get_string_value(sym); + printf("%s%s=%s\n", CONFIG_, sym->name, str); + } } - } else if (input_mode != oldnoconfig) { + } else { if (!conf_cnt++) - printf(_("*\n* Restart config...\n*\n")); + printf("*\n* Restart config...\n*\n"); rootEntry = menu_get_parent_menu(menu); conf(rootEntry); } @@ -443,8 +448,9 @@ static void check_conf(struct menu *menu) } static struct option long_opts[] = { - {"askconfig", no_argument, NULL, oldaskconfig}, - {"config", no_argument, NULL, oldconfig}, + {"oldaskconfig", no_argument, NULL, oldaskconfig}, + {"oldconfig", no_argument, NULL, oldconfig}, + {"syncconfig", no_argument, NULL, syncconfig}, {"defconfig", optional_argument, NULL, defconfig}, {"savedefconfig", required_argument, NULL, savedefconfig}, {"allnoconfig", no_argument, NULL, allnoconfig}, @@ -453,7 +459,7 @@ static struct option long_opts[] = { {"alldefconfig", no_argument, NULL, alldefconfig}, {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, - {"noconfig", no_argument, NULL, oldnoconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, {NULL, 0, NULL, 0} }; @@ -463,10 +469,11 @@ static void conf_usage(const char *progname) printf("Usage: %s [-s] [option] \n", progname); printf("[option] is _one_ of the following:\n"); printf(" --listnewconfig List new options\n"); - printf(" --askconfig Start a new configuration using a line-oriented program\n"); - printf(" --config Update a configuration using a provided .config as base\n"); - printf(" --silentconfig Same as config, but quietly, additionally update deps\n"); - printf(" --noconfig Same as silentconfig but set new symbols to no\n"); + printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); + printf(" --oldconfig Update a configuration using a provided .config as base\n"); + printf(" --syncconfig Similar to oldconfig but generates configuration in\n" + " include/{generated/,config/}\n"); + printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); printf(" --defconfig New config with default defined in \n"); printf(" --savedefconfig Save the minimal current configuration to \n"); printf(" --allnoconfig New config where all options are answered with no\n"); @@ -482,12 +489,9 @@ int main(int ac, char **av) int opt; const char *name, *defconfig_file = NULL /* gcc uninit */; struct stat tmpstat; + int no_conf_write = 0; - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - - tty_stdio = isatty(0) && isatty(1) && isatty(2); + tty_stdio = isatty(0) && isatty(1); while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) { if (opt == 's') { @@ -496,6 +500,14 @@ int main(int ac, char **av) } input_mode = (enum input_mode)opt; switch (opt) { + case syncconfig: + /* + * syncconfig is invoked during the build stage. + * Suppress distracting "configuration written to ..." + */ + conf_set_message_callback(NULL); + sync_kconfig = 1; + break; case defconfig: case savedefconfig: defconfig_file = optarg; @@ -532,7 +544,7 @@ int main(int ac, char **av) case allmodconfig: case alldefconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: break; case '?': conf_usage(progname); @@ -541,30 +553,45 @@ int main(int ac, char **av) } } if (ac == optind) { - printf(_("%s: Kconfig file missing\n"), av[0]); + fprintf(stderr, "%s: Kconfig file missing\n", av[0]); conf_usage(progname); exit(1); } name = av[optind]; conf_parse(name); //zconfdump(stdout); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, "***\n" + "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n", name); + exit(1); + } + } switch (input_mode) { case defconfig: if (!defconfig_file) defconfig_file = conf_get_default_confname(); if (conf_read(defconfig_file)) { - printf(_("***\n" - "*** Can't find default configuration \"%s\"!\n" - "***\n"), defconfig_file); + fprintf(stderr, + "***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n", + defconfig_file); exit(1); } break; case savedefconfig: + case syncconfig: case oldaskconfig: case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: conf_read(NULL); break; case allnoconfig: @@ -578,7 +605,7 @@ int main(int ac, char **av) if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { if (conf_read_simple(name, S_DEF_USER)) { fprintf(stderr, - _("*** Can't read seed configuration \"%s\"!\n"), + "*** Can't read seed configuration \"%s\"!\n", name); exit(1); } @@ -595,7 +622,7 @@ int main(int ac, char **av) if (conf_read_simple(name, S_DEF_USER) && conf_read_simple("all.config", S_DEF_USER)) { fprintf(stderr, - _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n", name); exit(1); } @@ -604,7 +631,17 @@ int main(int ac, char **av) break; } - valid_stdin = tty_stdio; + if (sync_kconfig) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + if (conf_get_changed()) { + fprintf(stderr, + "\n*** The configuration requires explicit update.\n\n"); + return 1; + } + no_conf_write = 1; + } + } switch (input_mode) { case allnoconfig: @@ -635,44 +672,51 @@ int main(int ac, char **av) /* fall through */ case oldconfig: case listnewconfig: - case oldnoconfig: + case syncconfig: /* Update until a loop caused no more changes */ do { conf_cnt = 0; check_conf(&rootmenu); - } while (conf_cnt && - (input_mode != listnewconfig && - input_mode != oldnoconfig)); + } while (conf_cnt); + break; + case olddefconfig: + default: break; } if (input_mode == savedefconfig) { if (conf_write_defconfig(defconfig_file)) { - fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n", defconfig_file); return 1; } } else if (input_mode != listnewconfig) { - /* - * build so we shall update autoconf. - */ - if (conf_write(NULL)) { - fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + if (!no_conf_write && conf_write(NULL)) { + fprintf(stderr, "\n*** Error during writing of the configuration.\n\n"); exit(1); } - if (conf_write_autoconf()) { - fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + + /* + * Create auto.conf if it does not exist. + * This prevents GNU Make 4.1 or older from emitting + * "include/generated/auto.conf: No such file or directory" + * in the top-level Makefile + * + * syncconfig always creates or updates auto.conf because it is + * used during the build. + */ + + /* + * In our cmake case, we always want to update the autogenerated + * files. + */ + sync_kconfig = 1; + + if (conf_write_autoconf(sync_kconfig) && sync_kconfig) { + fprintf(stderr, + "\n*** Error during sync of the configuration.\n\n"); return 1; } } return 0; } - -/* - * Helper function to facilitate fgets() by Jean Sacren. - */ -void xfgets(char *str, int size, FILE *in) -{ - if (fgets(str, size, in) == NULL) - fprintf(stderr, "\nError in reading or end of file.\n"); -} diff --git a/carl9170fw/config/confdata.c b/carl9170fw/config/confdata.c index e606f06..d67695d 100644 --- a/carl9170fw/config/confdata.c +++ b/carl9170fw/config/confdata.c @@ -1,12 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include +#include #include #include #include @@ -16,6 +17,105 @@ #include "lkc.h" +/* return true if 'path' exists, false otherwise */ +static bool is_present(const char *path) +{ + struct stat st; + + return !stat(path, &st); +} + +/* return true if 'path' exists and it is a directory, false otherwise */ +static bool is_dir(const char *path) +{ + struct stat st; + + if (stat(path, &st)) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* + * Create the parent directory of the given path. + * + * For example, if 'include/config/auto.conf' is given, create 'include/config'. + */ +static int make_parent_dir(const char *path) +{ + char tmp[PATH_MAX + 1]; + char *p; + + strncpy(tmp, path, sizeof(tmp)); + tmp[sizeof(tmp) - 1] = 0; + + /* Remove the base name. Just return if nothing is left */ + p = strrchr(tmp, '/'); + if (!p) + return 0; + *(p + 1) = 0; + + /* Just in case it is an absolute path */ + p = tmp; + while (*p == '/') + p++; + + while ((p = strchr(p, '/'))) { + *p = 0; + + /* skip if the directory exists */ + if (!is_dir(tmp) && mkdir(tmp, 0755)) + return -1; + + *p = '/'; + while (*p == '/') + p++; + } + + return 0; +} + +static char depfile_path[PATH_MAX]; +static size_t depfile_prefix_len; + +/* touch depfile for symbol 'name' */ +static int conf_touch_dep(const char *name) +{ + int fd, ret; + const char *s; + char *d, c; + + /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */ + if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path)) + return -1; + + d = depfile_path + depfile_prefix_len; + s = name; + + while ((c = *s++)) + *d++ = (c == '_') ? '/' : tolower(c); + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) + return -1; + + ret = make_parent_dir(depfile_path); + if (ret) + return ret; + + /* Try it again. */ + fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + return -1; + } + close(fd); + + return 0; +} + struct conf_printer { void (*print_symbol)(FILE *, struct symbol *, const char *, void *); void (*print_comment)(FILE *, const char *, void *); @@ -28,7 +128,7 @@ static void conf_message(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); static const char *conf_filename; -static int conf_lineno, conf_warnings, conf_unsaved; +static int conf_lineno, conf_warnings; const char conf_defname[] = "include/generated/defconfig"; @@ -43,16 +143,16 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } -static void conf_default_message_callback(const char *fmt, va_list ap) +static void conf_default_message_callback(const char *s) { printf("#\n# "); - vprintf(fmt, ap); + printf("%s", s); printf("\n#\n"); } -static void (*conf_message_callback) (const char *fmt, va_list ap) = +static void (*conf_message_callback)(const char *s) = conf_default_message_callback; -void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +void conf_set_message_callback(void (*fn)(const char *s)) { conf_message_callback = fn; } @@ -60,10 +160,15 @@ void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) static void conf_message(const char *fmt, ...) { va_list ap; + char buf[4096]; + + if (!conf_message_callback) + return; va_start(ap, fmt); - if (conf_message_callback) - conf_message_callback(fmt, ap); + + vsnprintf(buf, sizeof(buf), fmt, ap); + conf_message_callback(buf); va_end(ap); } @@ -81,43 +186,16 @@ const char *conf_get_autoconfig_name(void) return name ? name : "include/generated/auto.conf"; } -static char *conf_expand_value(const char *in) -{ - struct symbol *sym; - const char *src; - static char res_value[SYMBOL_MAXLENGTH]; - char *dst, name[SYMBOL_MAXLENGTH]; - - res_value[0] = 0; - dst = name; - while ((src = strchr(in, '$'))) { - strncat(res_value, in, src - in); - src++; - dst = name; - while (isalnum(*src) || *src == '_') - *dst++ = *src++; - *dst = 0; - sym = sym_lookup(name, 0); - sym_calc_value(sym); - strcat(res_value, sym_get_string_value(sym)); - in = src; - } - strcat(res_value, in); - - return res_value; -} - char *conf_get_default_confname(void) { - struct stat buf; static char fullname[PATH_MAX+1]; char *env, *name; - name = conf_expand_value(conf_defname); + name = expand_string(conf_defname); env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); - if (!stat(fullname, &buf)) + if (is_present(fullname)) return fullname; } return name; @@ -150,14 +228,6 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) conf_warning("symbol value '%s' invalid for %s", p, sym->name); return 1; - case S_OTHER: - if (*p != '"') { - for (p2 = p; *p2 && !isspace(*p2); p2++) - ; - sym->type = S_STRING; - goto done; - } - /* fall through */ case S_STRING: if (*p++ != '"') break; @@ -176,9 +246,8 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) /* fall through */ case S_INT: case S_HEX: - done: if (sym_string_valid(sym, p)) { - sym->def[def].val = strdup(p); + sym->def[def].val = xstrdup(p); sym->flags |= def_flags; } else { if (def != S_DEF_AUTO) @@ -201,7 +270,7 @@ static int add_byte(int c, char **lineptr, size_t slen, size_t *n) if (new_size > *n) { new_size += LINE_GROWTH - 1; new_size *= 2; - nline = realloc(*lineptr, new_size); + nline = xrealloc(*lineptr, new_size); if (!nline) return -1; @@ -274,10 +343,11 @@ int conf_read_simple(const char *name, int def) if (expr_calc_value(prop->visible.expr) == no || prop->expr->type != E_SYMBOL) continue; - name = conf_expand_value(prop->expr->left.sym->name); + sym_calc_value(prop->expr->left.sym); + name = sym_get_string_value(prop->expr->left.sym); in = zconf_fopen(name); if (in) { - conf_message(_("using defaults found in %s"), + conf_message("using defaults found in %s", name); goto load; } @@ -290,7 +360,6 @@ load: conf_filename = name; conf_lineno = 0; conf_warnings = 0; - conf_unsaved = 0; def_flags = SYMBOL_DEF << def; for_all_symbols(i, sym) { @@ -327,7 +396,7 @@ load: sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); - goto setsym; + continue; } } else { sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); @@ -357,17 +426,22 @@ load: if (*p2 == '\r') *p2 = 0; } - if (def == S_DEF_USER) { - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { + + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + if (def == S_DEF_AUTO) + /* + * Reading from include/config/auto.conf + * If CONFIG_FOO previously existed in + * auto.conf but it is missing now, + * include/config/foo.h must be touched. + */ + conf_touch_dep(line + strlen(CONFIG_)); + else sym_add_change_count(1); - goto setsym; - } - } else { - sym = sym_lookup(line + strlen(CONFIG_), 0); - if (sym->type == S_UNKNOWN) - sym->type = S_OTHER; + continue; } + if (sym->flags & def_flags) { conf_warning("override: reassigning to symbol %s", sym->name); } @@ -380,7 +454,7 @@ load: continue; } -setsym: + if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); switch (sym->def[def].tri) { @@ -409,6 +483,7 @@ setsym: int conf_read(const char *name) { struct symbol *sym; + int conf_unsaved = 0; int i; sym_set_change_count(0); @@ -422,7 +497,7 @@ int conf_read(const char *name) for_all_symbols(i, sym) { sym_calc_value(sym); - if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ @@ -678,7 +753,6 @@ static void conf_write_symbol(FILE *fp, struct symbol *sym, const char *str; switch (sym->type) { - case S_OTHER: case S_UNKNOWN: break; case S_STRING: @@ -791,15 +865,14 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; if (name && name[0]) { - struct stat st; char *slash; - if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + if (is_dir(name)) { strcpy(dirname, name); strcat(dirname, "/"); basename = conf_get_configname(); @@ -877,33 +950,61 @@ next: return 1; } - conf_message(_("configuration written to %s"), newname); + conf_message("configuration written to %s", newname); sym_set_change_count(0); return 0; } -static int conf_split_config(void) +/* write a dependency file as used by kbuild to track dependencies */ +static int conf_write_dep(const char *name) +{ + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + out = fopen("..config.tmp", "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + env_write_dep(out, conf_get_autoconfig_name()); + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + + if (make_parent_dir(name)) + return 1; + rename("..config.tmp", name); + return 0; +} + +static int conf_touch_deps(void) { const char *name; - char path[PATH_MAX+1]; - char *s, *d, c; struct symbol *sym; - struct stat sb; - int res, i, fd; + int res, i; + + strcpy(depfile_path, "include/generated/"); + depfile_prefix_len = strlen(depfile_path); name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); - if (chdir("include/generated")) - return 1; - - res = 0; for_all_symbols(i, sym) { sym_calc_value(sym); - if ((sym->flags & SYMBOL_AUTO) || !sym->name) + if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) continue; if (sym->flags & SYMBOL_WRITE) { if (sym->flags & SYMBOL_DEF_AUTO) { @@ -952,63 +1053,30 @@ static int conf_split_config(void) * different from 'no'). */ - /* Replace all '_' and append ".h" */ - s = sym->name; - d = path; - while ((c = *s++)) { - c = tolower(c); - *d++ = (c == '_') ? '/' : c; - } - strcpy(d, ".h"); - - /* Assume directory path already exists. */ - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - if (errno != ENOENT) { - res = 1; - break; - } - /* - * Create directory components, - * unless they exist already. - */ - d = path; - while ((d = strchr(d, '/'))) { - *d = 0; - if (stat(path, &sb) && mkdir(path, 0755)) { - res = 1; - goto out; - } - *d++ = '/'; - } - /* Try it again. */ - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - res = 1; - break; - } - } - close(fd); + res = conf_touch_dep(sym->name); + if (res) + return res; } -out: - if (chdir("../..")) - return 1; - return res; + return 0; } -int conf_write_autoconf(void) +int conf_write_autoconf(int overwrite) { struct symbol *sym; const char *name; + const char *autoconf_name = conf_get_autoconfig_name(); FILE *out, *tristate, *out_h, *out_c; int i; + if (!overwrite && is_present(autoconf_name)) + return 0; + sym_clear_all_valid(); - file_write_dep("include/generated/auto.conf.cmd"); + conf_write_dep("include/generated/auto.conf.cmd"); - if (conf_split_config()) + if (conf_touch_deps()) return 1; out = fopen(".tmpconfig", "w"); @@ -1065,24 +1133,35 @@ int conf_write_autoconf(void) name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; + if (make_parent_dir(name)) + return 1; if (rename(".tmpconfig.h", name)) return 1; + name = getenv("KCONFIG_TRISTATE"); if (!name) name = "include/generated/tristate.conf"; + if (make_parent_dir(name)) + return 1; if (rename(".tmpconfig_tristate", name)) return 1; + + if (make_parent_dir(autoconf_name)) + return 1; + name = getenv("KCONFIG_CMAKE"); if (!name) name = "config.cmake"; + if (make_parent_dir(name)) + return 1; if (rename(".tmpconfig.cmake", name)) return 1; - name = conf_get_autoconfig_name(); + /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */ - if (rename(".tmpconfig", name)) + if (rename(".tmpconfig", autoconf_name)) return 1; return 0; @@ -1186,7 +1265,7 @@ void set_all_choice_values(struct symbol *csym) bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; - int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + int i, cnt, pby, pty, ptm; /* pby: probability of bool = y * pty: probability of tristate = y * ptm: probability of tristate = m */ diff --git a/carl9170fw/config/expr.c b/carl9170fw/config/expr.c index 8cee597..77ffff3 100644 --- a/carl9170fw/config/expr.c +++ b/carl9170fw/config/expr.c @@ -1,8 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ +#include +#include #include #include #include @@ -94,7 +96,7 @@ struct expr *expr_copy(const struct expr *org) e->right.expr = expr_copy(org->right.expr); break; default: - printf("can't copy type %d\n", e->type); + fprintf(stderr, "can't copy type %d\n", e->type); free(e); e = NULL; break; @@ -113,7 +115,7 @@ void expr_free(struct expr *e) break; case E_NOT: expr_free(e->left.expr); - return; + break; case E_EQUAL: case E_GEQ: case E_GTH: @@ -127,7 +129,7 @@ void expr_free(struct expr *e) expr_free(e->right.expr); break; default: - printf("how to free type %d?\n", e->type); + fprintf(stderr, "how to free type %d?\n", e->type); break; } free(e); @@ -138,8 +140,18 @@ static int trans_count; #define e1 (*ep1) #define e2 (*ep2) +/* + * expr_eliminate_eq() helper. + * + * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does + * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared + * against all other leaves. Two equal leaves are both replaced with either 'y' + * or 'n' as appropriate for 'type', to be eliminated later. + */ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) { + /* Recurse down to leaves */ + if (e1->type == type) { __expr_eliminate_eq(type, &e1->left.expr, &e2); __expr_eliminate_eq(type, &e1->right.expr, &e2); @@ -150,12 +162,18 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e __expr_eliminate_eq(type, &e1, &e2->right.expr); return; } + + /* e1 and e2 are leaves. Compare them. */ + if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym && (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) return; if (!expr_eq(e1, e2)) return; + + /* e1 and e2 are equal leaves. Prepare them for elimination. */ + trans_count++; expr_free(e1); expr_free(e2); switch (type) { @@ -172,6 +190,35 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e } } +/* + * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both. + * Example reductions: + * + * ep1: A && B -> ep1: y + * ep2: A && B && C -> ep2: C + * + * ep1: A || B -> ep1: n + * ep2: A || B || C -> ep2: C + * + * ep1: A && (B && FOO) -> ep1: FOO + * ep2: (BAR && B) && A -> ep2: BAR + * + * ep1: A && (B || C) -> ep1: y + * ep2: (C || B) && A -> ep2: y + * + * Comparisons are done between all operands at the same "level" of && or ||. + * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the + * following operands will be compared: + * + * - 'e1', 'e2 || e3', and 'e4 || e5', against each other + * - e2 against e3 + * - e4 against e5 + * + * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and + * '(e1 && e2) && e3' are both a single level. + * + * See __expr_eliminate_eq() as well. + */ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) { if (!e1 || !e2) @@ -197,6 +244,12 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) #undef e1 #undef e2 +/* + * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two + * &&/|| expressions are considered equal if every operand in one expression + * equals some operand in the other (operands do not need to appear in the same + * order), recursively. + */ static int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; @@ -243,6 +296,17 @@ static int expr_eq(struct expr *e1, struct expr *e2) return 0; } +/* + * Recursively performs the following simplifications in-place (as well as the + * corresponding simplifications with swapped operands): + * + * expr && n -> n + * expr && y -> expr + * expr || n -> expr + * expr || y -> y + * + * Returns the optimized expression. + */ static struct expr *expr_eliminate_yn(struct expr *e) { struct expr *tmp; @@ -516,12 +580,21 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2) return NULL; } +/* + * expr_eliminate_dups() helper. + * + * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does + * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared + * against all other leaves to look for simplifications. + */ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) { #define e1 (*ep1) #define e2 (*ep2) struct expr *tmp; + /* Recurse down to leaves */ + if (e1->type == type) { expr_eliminate_dups1(type, &e1->left.expr, &e2); expr_eliminate_dups1(type, &e1->right.expr, &e2); @@ -532,6 +605,9 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr_eliminate_dups1(type, &e1, &e2->right.expr); return; } + + /* e1 and e2 are leaves. Compare and process them. */ + if (e1 == e2) return; @@ -568,6 +644,17 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct #undef e2 } +/* + * Rewrites 'e' in-place to remove ("join") duplicate and other redundant + * operands. + * + * Example simplifications: + * + * A || B || A -> A || B + * A && B && A=y -> A=y && B + * + * Returns the deduplicated expression. + */ struct expr *expr_eliminate_dups(struct expr *e) { int oldcount; @@ -584,6 +671,7 @@ struct expr *expr_eliminate_dups(struct expr *e) ; } if (!trans_count) + /* No simplifications done in this pass. We're done */ break; e = expr_eliminate_yn(e); } @@ -591,6 +679,12 @@ struct expr *expr_eliminate_dups(struct expr *e) return e; } +/* + * Performs various simplifications involving logical operators and + * comparisons. + * + * Allocates and returns a new expression. + */ struct expr *expr_transform(struct expr *e) { struct expr *tmp; @@ -805,6 +899,20 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym) return false; } +/* + * Inserts explicit comparisons of type 'type' to symbol 'sym' into the + * expression 'e'. + * + * Examples transformations for type == E_UNEQUAL, sym == &symbol_no: + * + * A -> A!=n + * !A -> A=n + * A && B -> !(A=n || B=n) + * A || B -> !(A=n && B=n) + * A && (B || C) -> !(A=n || (B=n && C=n)) + * + * Allocates and returns a new expression. + */ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) { struct expr *e1, *e2; @@ -874,7 +982,6 @@ enum string_value_kind { k_string, k_signed, k_unsigned, - k_invalid }; union string_value { @@ -905,13 +1012,10 @@ static enum string_value_kind expr_parse_string(const char *str, val->u = strtoull(str, &tail, 16); kind = k_unsigned; break; - case S_STRING: - case S_UNKNOWN: + default: val->s = strtoll(str, &tail, 0); kind = k_signed; break; - default: - return k_invalid; } return !errno && !*tail && tail > str && isxdigit(tail[-1]) ? kind : k_string; @@ -967,13 +1071,7 @@ tristate expr_calc_value(struct expr *e) if (k1 == k_string || k2 == k_string) res = strcmp(str1, str2); - else if (k1 == k_invalid || k2 == k_invalid) { - if (e->type != E_EQUAL && e->type != E_UNEQUAL) { - printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2); - return no; - } - res = strcmp(str1, str2); - } else if (k1 == k_unsigned || k2 == k_unsigned) + else if (k1 == k_unsigned || k2 == k_unsigned) res = (lval.u > rval.u) - (lval.u < rval.u); else /* if (k1 == k_signed && k2 == k_signed) */ res = (lval.s > rval.s) - (lval.s < rval.s); @@ -1031,49 +1129,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2) return 0; } -static inline struct expr * -expr_get_leftmost_symbol(const struct expr *e) -{ - - if (e == NULL) - return NULL; - - while (e->type != E_SYMBOL) - e = e->left.expr; - - return expr_copy(e); -} - -/* - * Given expression `e1' and `e2', returns the leaf of the longest - * sub-expression of `e1' not containing 'e2. - */ -struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) -{ - struct expr *ret; - - switch (e1->type) { - case E_OR: - return expr_alloc_and( - expr_simplify_unmet_dep(e1->left.expr, e2), - expr_simplify_unmet_dep(e1->right.expr, e2)); - case E_AND: { - struct expr *e; - e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); - e = expr_eliminate_dups(e); - ret = (!expr_eq(e, e1)) ? e1 : NULL; - expr_free(e); - break; - } - default: - ret = e1; - break; - } - - return expr_get_leftmost_symbol(ret); -} - -void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) +void expr_print(struct expr *e, + void (*fn)(void *, struct symbol *, const char *), + void *data, int prevtoken) { if (!e) { fn(data, NULL, "y"); @@ -1207,3 +1265,33 @@ void expr_gstr_print(struct expr *e, struct gstr *gs) { expr_print(e, expr_print_gstr_helper, gs, E_NONE); } + +/* + * Transform the top level "||" tokens into newlines and prepend each + * line with a minus. This makes expressions much easier to read. + * Suitable for reverse dependency expressions. + */ +static void expr_print_revdep(struct expr *e, + void (*fn)(void *, struct symbol *, const char *), + void *data, tristate pr_type, const char **title) +{ + if (e->type == E_OR) { + expr_print_revdep(e->left.expr, fn, data, pr_type, title); + expr_print_revdep(e->right.expr, fn, data, pr_type, title); + } else if (expr_calc_value(e) == pr_type) { + if (*title) { + fn(data, NULL, *title); + *title = NULL; + } + + fn(data, NULL, " - "); + expr_print(e, fn, data, E_NONE); + fn(data, NULL, "\n"); + } +} + +void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, + tristate pr_type, const char *title) +{ + expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title); +} diff --git a/carl9170fw/config/expr.h b/carl9170fw/config/expr.h index a73f762..999edb6 100644 --- a/carl9170fw/config/expr.h +++ b/carl9170fw/config/expr.h @@ -1,6 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ #ifndef EXPR_H @@ -62,7 +62,7 @@ struct symbol_value { }; enum symbol_type { - S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER + S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING }; /* enum values are used as index to symbol.def[] */ @@ -74,21 +74,64 @@ enum { S_DEF_COUNT }; +/* + * Represents a configuration symbol. + * + * Choices are represented as a special kind of symbol and have the + * SYMBOL_CHOICE bit set in 'flags'. + */ struct symbol { + /* The next symbol in the same bucket in the symbol hash table */ struct symbol *next; + + /* The name of the symbol, e.g. "FOO" for 'config FOO' */ char *name; + + /* S_BOOLEAN, S_TRISTATE, ... */ enum symbol_type type; + + /* + * The calculated value of the symbol. The SYMBOL_VALID bit is set in + * 'flags' when this is up to date. Note that this value might differ + * from the user value set in e.g. a .config file, due to visibility. + */ struct symbol_value curr; + + /* + * Values for the symbol provided from outside. def[S_DEF_USER] holds + * the .config value. + */ struct symbol_value def[S_DEF_COUNT]; + + /* + * An upper bound on the tristate value the user can set for the symbol + * if it is a boolean or tristate. Calculated from prompt dependencies, + * which also inherit dependencies from enclosing menus, choices, and + * ifs. If 'n', the user value will be ignored. + * + * Symbols lacking prompts always have visibility 'n'. + */ tristate visible; + + /* SYMBOL_* flags */ int flags; + + /* List of properties. See prop_type. */ struct property *prop; + + /* Dependencies from enclosing menus, choices, and ifs */ struct expr_value dir_dep; + + /* Reverse dependencies through being selected by other symbols */ struct expr_value rev_dep; + + /* + * "Weak" reverse dependencies through being implied by other symbols + */ struct expr_value implied; }; -#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ @@ -98,7 +141,7 @@ struct symbol { #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_CHANGED 0x0400 /* ? */ -#define SYMBOL_AUTO 0x1000 /* value from environment variable */ +#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */ #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ #define SYMBOL_WARNED 0x8000 /* warning has been issued */ @@ -128,18 +171,20 @@ struct symbol { * config BAZ * int "BAZ Value" * range 1..255 + * + * Please, also check zconf.y:print_symbol() when modifying the + * list of property types! */ enum prop_type { P_UNKNOWN, P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ P_COMMENT, /* text associated with a comment */ - P_MENU, /* prompt associated with a menuconfig option */ + P_MENU, /* prompt associated with a menu or menuconfig symbol */ P_DEFAULT, /* default y */ P_CHOICE, /* choice value */ P_SELECT, /* select BAR */ P_IMPLY, /* imply BAR */ P_RANGE, /* range 7..100 (for a symbol) */ - P_ENV, /* value from environment variable */ P_SYMBOL, /* where a symbol is defined */ }; @@ -166,22 +211,67 @@ struct property { for (st = sym->prop; st; st = st->next) \ if (st->text) +/* + * Represents a node in the menu tree, as seen in e.g. menuconfig (though used + * for all front ends). Each symbol, menu, etc. defined in the Kconfig files + * gets a node. A symbol defined in multiple locations gets one node at each + * location. + */ struct menu { + /* The next menu node at the same level */ struct menu *next; + + /* The parent menu node, corresponding to e.g. a menu or choice */ struct menu *parent; + + /* The first child menu node, for e.g. menus and choices */ struct menu *list; + + /* + * The symbol associated with the menu node. Choices are implemented as + * a special kind of symbol. NULL for menus, comments, and ifs. + */ struct symbol *sym; + + /* + * The prompt associated with the node. This holds the prompt for a + * symbol as well as the text for a menu or comment, along with the + * type (P_PROMPT, P_MENU, etc.) + */ struct property *prompt; + + /* + * 'visible if' dependencies. If more than one is given, they will be + * ANDed together. + */ struct expr *visibility; + + /* + * Ordinary dependencies from e.g. 'depends on' and 'if', ANDed + * together + */ struct expr *dep; + + /* MENU_* flags */ unsigned int flags; + + /* Any help text associated with the node */ char *help; + + /* The location where the menu node appears in the Kconfig files */ struct file *file; int lineno; + + /* For use by front ends that need to store auxiliary data */ void *data; }; +/* + * Set on a menu node when the corresponding symbol changes state in some way. + * Can be checked by front ends. + */ #define MENU_CHANGED 0x0001 + #define MENU_ROOT 0x0002 struct jump_key { @@ -217,11 +307,12 @@ struct expr *expr_transform(struct expr *e); int expr_contains_symbol(struct expr *dep, struct symbol *sym); bool expr_depends_symbol(struct expr *dep, struct symbol *sym); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); -struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); void expr_fprint(struct expr *e, FILE *out); struct gstr; /* forward */ void expr_gstr_print(struct expr *e, struct gstr *gs); +void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, + tristate pr_type, const char *title); static inline int expr_is_yes(struct expr *e) { diff --git a/carl9170fw/config/kconf_id.c b/carl9170fw/config/kconf_id.c deleted file mode 100644 index 5abbc72..0000000 --- a/carl9170fw/config/kconf_id.c +++ /dev/null @@ -1,54 +0,0 @@ - -static struct kconf_id kconf_id_array[] = { - { "mainmenu", T_MAINMENU, TF_COMMAND }, - { "menu", T_MENU, TF_COMMAND }, - { "endmenu", T_ENDMENU, TF_COMMAND }, - { "source", T_SOURCE, TF_COMMAND }, - { "choice", T_CHOICE, TF_COMMAND }, - { "endchoice", T_ENDCHOICE, TF_COMMAND }, - { "comment", T_COMMENT, TF_COMMAND }, - { "config", T_CONFIG, TF_COMMAND }, - { "menuconfig", T_MENUCONFIG, TF_COMMAND }, - { "help", T_HELP, TF_COMMAND }, - { "---help---", T_HELP, TF_COMMAND }, - { "if", T_IF, TF_COMMAND|TF_PARAM }, - { "endif", T_ENDIF, TF_COMMAND }, - { "depends", T_DEPENDS, TF_COMMAND }, - { "optional", T_OPTIONAL, TF_COMMAND }, - { "default", T_DEFAULT, TF_COMMAND, S_UNKNOWN }, - { "prompt", T_PROMPT, TF_COMMAND }, - { "tristate", T_TYPE, TF_COMMAND, S_TRISTATE }, - { "def_tristate", T_DEFAULT, TF_COMMAND, S_TRISTATE }, - { "bool", T_TYPE, TF_COMMAND, S_BOOLEAN }, - { "boolean", T_TYPE, TF_COMMAND, S_BOOLEAN }, - { "def_bool", T_DEFAULT, TF_COMMAND, S_BOOLEAN }, - { "int", T_TYPE, TF_COMMAND, S_INT }, - { "hex", T_TYPE, TF_COMMAND, S_HEX }, - { "string", T_TYPE, TF_COMMAND, S_STRING }, - { "select", T_SELECT, TF_COMMAND }, - { "imply", T_IMPLY, TF_COMMAND }, - { "range", T_RANGE, TF_COMMAND }, - { "visible", T_VISIBLE, TF_COMMAND }, - { "option", T_OPTION, TF_COMMAND }, - { "on", T_ON, TF_PARAM }, - { "modules", T_OPT_MODULES, TF_OPTION }, - { "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION }, - { "env", T_OPT_ENV, TF_OPTION }, - { "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION }, -}; - -#define KCONF_ID_ARRAY_SIZE (sizeof(kconf_id_array)/sizeof(struct kconf_id)) - -static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len) -{ - int i; - - for (i = 0; i < KCONF_ID_ARRAY_SIZE; i++) { - struct kconf_id *id = kconf_id_array+i; - int l = strlen(id->name); - - if (len == l && !memcmp(str, id->name, len)) - return id; - } - return NULL; -} diff --git a/carl9170fw/config/lkc.h b/carl9170fw/config/lkc.h index cdcbe43..531ff7c 100644 --- a/carl9170fw/config/lkc.h +++ b/carl9170fw/config/lkc.h @@ -1,6 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ #ifndef LKC_H @@ -8,15 +8,6 @@ #include "expr.h" -#ifndef KBUILD_NO_NLS -# include -#else -static inline const char *gettext(const char *txt) { return txt; } -static inline void textdomain(const char *domainname) {} -static inline void bindtextdomain(const char *name, const char *dir) {} -static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } -#endif - #ifdef __cplusplus extern "C" { #endif @@ -29,11 +20,6 @@ extern "C" { #define PACKAGE "linux" #endif -#define LOCALEDIR "/usr/share/locale" - -#define _(text) gettext(text) -#define N_(text) (text) - #ifndef CONFIG_ #define CONFIG_ "CONFIG_" #endif @@ -44,10 +30,6 @@ static inline const char *CONFIG_prefix(void) #undef CONFIG_ #define CONFIG_ CONFIG_prefix() -#define TF_COMMAND 0x0001 -#define TF_PARAM 0x0002 -#define TF_OPTION 0x0004 - enum conf_def_mode { def_default, def_yes, @@ -56,18 +38,7 @@ enum conf_def_mode { def_random }; -#define T_OPT_MODULES 1 -#define T_OPT_DEFCONFIG_LIST 2 -#define T_OPT_ENV 3 -#define T_OPT_ALLNOCONFIG_Y 4 - -struct kconf_id { - const char *name; - int token; - unsigned int flags; - enum symbol_type stype; -}; - +extern int yylineno; void zconfdump(FILE *out); void zconf_starthelp(void); FILE *zconf_fopen(const char *name); @@ -100,21 +71,27 @@ void menu_warn(struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); void menu_end_menu(void); void menu_add_entry(struct symbol *sym); -void menu_end_entry(void); void menu_add_dep(struct expr *dep); void menu_add_visibility(struct expr *dep); struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_add_option(int token, char *arg); +void menu_add_option_modules(void); +void menu_add_option_defconfig_list(void); +void menu_add_option_allnoconfig_y(void); void menu_finalize(struct menu *parent); void menu_set_type(int type); /* util.c */ struct file *file_lookup(const char *name); -int file_write_dep(const char *name); void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); +void *xrealloc(void *p, size_t size); +char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t n); + +/* zconf.l */ +int yylex(void); struct gstr { size_t len; @@ -132,16 +109,13 @@ void str_printf(struct gstr *gs, const char *fmt, ...); const char *str_get(struct gstr *gs); /* symbol.c */ -extern struct expr *sym_env_list; - -void sym_init(void); void sym_clear_all_valid(void); struct symbol *sym_choice_default(struct symbol *sym); +struct property *sym_get_range_prop(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym); struct property *prop_alloc(enum prop_type type, struct symbol *sym); struct symbol *prop_get_symbol(struct property *prop); -struct property *sym_get_env_prop(struct symbol *sym); static inline tristate sym_get_tristate_value(struct symbol *sym) { diff --git a/carl9170fw/config/lkc_proto.h b/carl9170fw/config/lkc_proto.h index 5d86e2d..86c2675 100644 --- a/carl9170fw/config/lkc_proto.h +++ b/carl9170fw/config/lkc_proto.h @@ -7,10 +7,10 @@ int conf_read(const char *name); int conf_read_simple(const char *name, int); int conf_write_defconfig(const char *name); int conf_write(const char *name); -int conf_write_autoconf(void); +int conf_write_autoconf(int overwrite); bool conf_get_changed(void); void conf_set_changed_callback(void (*fn)(void)); -void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap)); +void conf_set_message_callback(void (*fn)(const char *s)); /* menu.c */ extern struct menu rootmenu; @@ -31,7 +31,6 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_find(const char *name); -const char * sym_expand_string_value(const char *in); const char * sym_escape_string_value(const char *in); struct symbol ** sym_re_search(const char *pattern); const char * sym_type_name(enum symbol_type type); @@ -49,5 +48,19 @@ const char * sym_get_string_value(struct symbol *sym); const char * prop_get_type_name(enum prop_type type); +/* preprocess.c */ +enum variable_flavor { + VAR_SIMPLE, + VAR_RECURSIVE, + VAR_APPEND, +}; +void env_write_dep(FILE *f, const char *auto_conf_name); +void variable_add(const char *name, const char *value, + enum variable_flavor flavor); +void variable_all_del(void); +char *expand_string(const char *in); +char *expand_dollar(const char **str); +char *expand_one_token(const char **str); + /* expr.c */ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/carl9170fw/config/menu.c b/carl9170fw/config/menu.c index e935793..d9d1646 100644 --- a/carl9170fw/config/menu.c +++ b/carl9170fw/config/menu.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ #include @@ -62,13 +62,8 @@ void menu_add_entry(struct symbol *sym) menu_add_symbol(P_SYMBOL, sym, NULL); } -void menu_end_entry(void) -{ -} - struct menu *menu_add_menu(void) { - menu_end_entry(); last_entry_ptr = ¤t_entry->list; return current_menu = current_entry; } @@ -79,19 +74,23 @@ void menu_end_menu(void) current_menu = current_menu->parent; } -static struct expr *menu_check_dep(struct expr *e) +/* + * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running + * without modules + */ +static struct expr *rewrite_m(struct expr *e) { if (!e) return e; switch (e->type) { case E_NOT: - e->left.expr = menu_check_dep(e->left.expr); + e->left.expr = rewrite_m(e->left.expr); break; case E_OR: case E_AND: - e->left.expr = menu_check_dep(e->left.expr); - e->right.expr = menu_check_dep(e->right.expr); + e->left.expr = rewrite_m(e->left.expr); + e->right.expr = rewrite_m(e->right.expr); break; case E_SYMBOL: /* change 'm' into 'm' && MODULES */ @@ -106,7 +105,7 @@ static struct expr *menu_check_dep(struct expr *e) void menu_add_dep(struct expr *dep) { - current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); + current_entry->dep = expr_alloc_and(current_entry->dep, dep); } void menu_set_type(int type) @@ -131,7 +130,7 @@ static struct property *menu_add_prop(enum prop_type type, char *prompt, struct prop->menu = current_entry; prop->expr = expr; - prop->visible.expr = menu_check_dep(dep); + prop->visible.expr = dep; if (prompt) { if (isspace(*prompt)) { @@ -196,31 +195,26 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); } -void menu_add_option(int token, char *arg) +void menu_add_option_modules(void) { - switch (token) { - case T_OPT_MODULES: - if (modules_sym) - zconf_error("symbol '%s' redefines option 'modules'" - " already defined by symbol '%s'", - current_entry->sym->name, - modules_sym->name - ); - modules_sym = current_entry->sym; - break; - case T_OPT_DEFCONFIG_LIST: - if (!sym_defconfig_list) - sym_defconfig_list = current_entry->sym; - else if (sym_defconfig_list != current_entry->sym) - zconf_error("trying to redefine defconfig symbol"); - break; - case T_OPT_ENV: - prop_add_env(arg); - break; - case T_OPT_ALLNOCONFIG_Y: - current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; - break; - } + if (modules_sym) + zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", + current_entry->sym->name, modules_sym->name); + modules_sym = current_entry->sym; +} + +void menu_add_option_defconfig_list(void) +{ + if (!sym_defconfig_list) + sym_defconfig_list = current_entry->sym; + else if (sym_defconfig_list != current_entry->sym) + zconf_error("trying to redefine defconfig symbol"); + sym_defconfig_list->flags |= SYMBOL_NO_WRITE; +} + +void menu_add_option_allnoconfig_y(void) +{ + current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; } static int menu_validate_number(struct symbol *sym, struct symbol *sym2) @@ -252,6 +246,16 @@ static void sym_check_prop(struct symbol *sym) "'%s': number is invalid", sym->name); } + if (sym_is_choice(sym)) { + struct property *choice_prop = + sym_get_choice_prop(sym2); + + if (!choice_prop || + prop_get_symbol(choice_prop) != sym) + prop_warn(prop, + "choice default symbol '%s' is not contained in the choice", + sym2->name); + } break; case P_SELECT: case P_IMPLY: @@ -260,13 +264,13 @@ static void sym_check_prop(struct symbol *sym) if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) prop_warn(prop, "config symbol '%s' uses %s, but is " - "not boolean or tristate", sym->name, use); + "not bool or tristate", sym->name, use); else if (sym2->type != S_UNKNOWN && sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE) prop_warn(prop, "'%s' has wrong type. '%s' only " - "accept arguments of boolean and " + "accept arguments of bool and " "tristate type", sym2->name, use); break; case P_RANGE: @@ -292,6 +296,11 @@ void menu_finalize(struct menu *parent) sym = parent->sym; if (parent->list) { + /* + * This menu node has children. We (recursively) process them + * and propagate parent dependencies before moving on. + */ + if (sym && sym_is_choice(sym)) { if (sym->type == S_UNKNOWN) { /* find the first choice value to find out choice type */ @@ -309,30 +318,83 @@ void menu_finalize(struct menu *parent) if (menu->sym && menu->sym->type == S_UNKNOWN) menu_set_type(sym->type); } + + /* + * Use the choice itself as the parent dependency of + * the contained items. This turns the mode of the + * choice into an upper bound on the visibility of the + * choice value symbols. + */ parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) + /* Menu node for 'menu' */ parentdep = parent->prompt->visible.expr; else + /* Menu node for 'if' */ parentdep = parent->dep; + /* For each child menu node... */ for (menu = parent->list; menu; menu = menu->next) { - basedep = expr_transform(menu->dep); + /* + * Propagate parent dependencies to the child menu + * node, also rewriting and simplifying expressions + */ + basedep = rewrite_m(menu->dep); + basedep = expr_transform(basedep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; + if (menu->sym) + /* + * Note: For symbols, all prompts are included + * too in the symbol's own property list + */ prop = menu->sym->prop; else + /* + * For non-symbol menu nodes, we just need to + * handle the prompt + */ prop = menu->prompt; + + /* For each property... */ for (; prop; prop = prop->next) { if (prop->menu != menu) + /* + * Two possibilities: + * + * 1. The property lacks dependencies + * and so isn't location-specific, + * e.g. an 'option' + * + * 2. The property belongs to a symbol + * defined in multiple locations and + * is from some other location. It + * will be handled there in that + * case. + * + * Skip the property. + */ continue; - dep = expr_transform(prop->visible.expr); + + /* + * Propagate parent dependencies to the + * property's condition, rewriting and + * simplifying expressions at the same time + */ + dep = rewrite_m(prop->visible.expr); + dep = expr_transform(dep); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); prop->visible.expr = dep; + + /* + * Handle selects and implies, which modify the + * dependencies of the selected/implied symbol + */ if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, @@ -344,34 +406,81 @@ void menu_finalize(struct menu *parent) } } } + + if (sym && sym_is_choice(sym)) + expr_free(parentdep); + + /* + * Recursively process children in the same fashion before + * moving on + */ for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym) { + /* + * Automatic submenu creation. If sym is a symbol and A, B, C, + * ... are consecutive items (symbols, menus, ifs, etc.) that + * all depend on sym, then the following menu structure is + * created: + * + * sym + * +-A + * +-B + * +-C + * ... + * + * This also works recursively, giving the following structure + * if A is a symbol and B depends on A: + * + * sym + * +-A + * | +-B + * +-C + * ... + */ + basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); + + /* Examine consecutive elements after sym */ last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) + /* No dependency, quit */ break; if (expr_depends_symbol(dep, sym)) + /* Absolute dependency, put in submenu */ goto next; + + /* + * Also consider it a dependency on sym if our + * dependencies contain sym and are a "superset" of + * sym's dependencies, e.g. '(sym || Q) && R' when sym + * depends on R. + * + * Note that 'R' might be from an enclosing menu or if, + * making this a more common case than it might seem. + */ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { + /* Not superset, quit */ expr_free(dep2); break; } + /* Superset, put in submenu */ expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } + expr_free(basedep); if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; @@ -420,6 +529,35 @@ void menu_finalize(struct menu *parent) *ep = expr_alloc_one(E_LIST, NULL); (*ep)->right.sym = menu->sym; } + + /* + * This code serves two purposes: + * + * (1) Flattening 'if' blocks, which do not specify a submenu + * and only add dependencies. + * + * (Automatic submenu creation might still create a submenu + * from an 'if' before this code runs.) + * + * (2) "Undoing" any automatic submenus created earlier below + * promptless symbols. + * + * Before: + * + * A + * if ... (or promptless symbol) + * +-B + * +-C + * D + * + * After: + * + * A + * if ... (or promptless symbol) + * B + * C + * D + */ if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { last_menu->parent = parent; @@ -444,6 +582,15 @@ void menu_finalize(struct menu *parent) sym->flags |= SYMBOL_WARNED; } + /* + * For non-optional choices, add a reverse dependency (corresponding to + * a select) of ' && m'. This prevents the user from + * setting the choice mode to 'n' when the choice is visible. + * + * This would also work for non-choice symbols, but only non-optional + * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented + * as a type of symbol. + */ if (sym && !sym_is_optional(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, @@ -558,7 +705,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, struct menu *submenu[8], *menu, *location = NULL; struct jump_key *jump = NULL; - str_printf(r, _("Prompt: %s\n"), _(prop->text)); + str_printf(r, "Prompt: %s\n", prop->text); menu = prop->menu->parent; for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); @@ -591,16 +738,16 @@ static void get_prompt_str(struct gstr *r, struct property *prop, } if (i > 0) { - str_printf(r, _(" Location:\n")); + str_printf(r, " Location:\n"); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; if (jump && menu == location) jump->offset = strlen(r->s); str_printf(r, "%*c-> %s", j, ' ', - _(menu_get_prompt(menu))); + menu_get_prompt(menu)); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? - menu->sym->name : _(""), + menu->sym->name : "", sym_get_string_value(menu->sym)); } str_append(r, "\n"); @@ -664,27 +811,27 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, prop = get_symbol_prop(sym); if (prop) { - str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, + str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, prop->menu->lineno); if (!expr_is_yes(prop->visible.expr)) { - str_append(r, _(" Depends on: ")); + str_append(r, " Depends on: "); expr_gstr_print(prop->visible.expr, r); str_append(r, "\n"); } } - get_symbol_props_str(r, sym, P_SELECT, _(" Selects: ")); + get_symbol_props_str(r, sym, P_SELECT, " Selects: "); if (sym->rev_dep.expr) { - str_append(r, _(" Selected by: ")); - expr_gstr_print(sym->rev_dep.expr, r); - str_append(r, "\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n"); } - get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: ")); + get_symbol_props_str(r, sym, P_IMPLY, " Implies: "); if (sym->implied.expr) { - str_append(r, _(" Implied by: ")); - expr_gstr_print(sym->implied.expr, r); - str_append(r, "\n"); + expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n"); + expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n"); + expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n"); } str_append(r, "\n\n"); @@ -699,7 +846,7 @@ struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) for (i = 0; sym_arr && (sym = sym_arr[i]); i++) get_symbol_str(&res, sym, head); if (!i) - str_append(&res, _("No matches found.\n")); + str_append(&res, "No matches found.\n"); return res; } @@ -714,7 +861,7 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); help_text = menu_get_help(menu); } - str_printf(help, "%s\n", _(help_text)); + str_printf(help, "%s\n", help_text); if (sym) get_symbol_str(help, sym, NULL); } diff --git a/carl9170fw/config/preprocess.c b/carl9170fw/config/preprocess.c new file mode 100644 index 0000000..592dfbf --- /dev/null +++ b/carl9170fw/config/preprocess.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 Masahiro Yamada + +#include +#include +#include +#include +#include +#include + +#include "list.h" +#include "lkc.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static char *expand_string_with_args(const char *in, int argc, char *argv[]); + +static void __attribute__((noreturn)) pperror(const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", current_file->name, yylineno); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} + +/* + * Environment variables + */ +static LIST_HEAD(env_list); + +struct env { + char *name; + char *value; + struct list_head node; +}; + +static void env_add(const char *name, const char *value) +{ + struct env *e; + + e = xmalloc(sizeof(*e)); + e->name = xstrdup(name); + e->value = xstrdup(value); + + list_add_tail(&e->node, &env_list); +} + +static void env_del(struct env *e) +{ + list_del(&e->node); + free(e->name); + free(e->value); + free(e); +} + +/* The returned pointer must be freed when done */ +static char *env_expand(const char *name) +{ + struct env *e; + const char *value; + + if (!*name) + return NULL; + + list_for_each_entry(e, &env_list, node) { + if (!strcmp(name, e->name)) + return xstrdup(e->value); + } + + value = getenv(name); + if (!value) + return NULL; + + /* + * We need to remember all referenced environment variables. + * They will be written out to include/config/auto.conf.cmd + */ + env_add(name, value); + + return xstrdup(value); +} + +void env_write_dep(FILE *f, const char *autoconfig_name) +{ + struct env *e, *tmp; + + list_for_each_entry_safe(e, tmp, &env_list, node) { + fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value); + fprintf(f, "%s: FORCE\n", autoconfig_name); + fprintf(f, "endif\n"); + env_del(e); + } +} + +/* + * Built-in functions + */ +struct function { + const char *name; + unsigned int min_args; + unsigned int max_args; + char *(*func)(int argc, char *argv[]); +}; + +static char *do_error_if(int argc, char *argv[]) +{ + if (!strcmp(argv[0], "y")) + pperror("%s", argv[1]); + + return NULL; +} + +static char *do_filename(int argc, char *argv[]) +{ + return xstrdup(current_file->name); +} + +static char *do_info(int argc, char *argv[]) +{ + printf("%s\n", argv[0]); + + return xstrdup(""); +} + +static char *do_lineno(int argc, char *argv[]) +{ + char buf[16]; + + sprintf(buf, "%d", yylineno); + + return xstrdup(buf); +} + +static char *do_shell(int argc, char *argv[]) +{ + FILE *p; + char buf[256]; + char *cmd; + size_t nread; + int i; + + cmd = argv[0]; + + p = popen(cmd, "r"); + if (!p) { + perror(cmd); + exit(1); + } + + nread = fread(buf, 1, sizeof(buf), p); + if (nread == sizeof(buf)) + nread--; + + /* remove trailing new lines */ + while (nread > 0 && buf[nread - 1] == '\n') + nread--; + + buf[nread] = 0; + + /* replace a new line with a space */ + for (i = 0; i < nread; i++) { + if (buf[i] == '\n') + buf[i] = ' '; + } + + if (pclose(p) == -1) { + perror(cmd); + exit(1); + } + + return xstrdup(buf); +} + +static char *do_warning_if(int argc, char *argv[]) +{ + if (!strcmp(argv[0], "y")) + fprintf(stderr, "%s:%d: %s\n", + current_file->name, yylineno, argv[1]); + + return xstrdup(""); +} + +static const struct function function_table[] = { + /* Name MIN MAX Function */ + { "error-if", 2, 2, do_error_if }, + { "filename", 0, 0, do_filename }, + { "info", 1, 1, do_info }, + { "lineno", 0, 0, do_lineno }, + { "shell", 1, 1, do_shell }, + { "warning-if", 2, 2, do_warning_if }, +}; + +#define FUNCTION_MAX_ARGS 16 + +static char *function_expand(const char *name, int argc, char *argv[]) +{ + const struct function *f; + int i; + + for (i = 0; i < ARRAY_SIZE(function_table); i++) { + f = &function_table[i]; + if (strcmp(f->name, name)) + continue; + + if (argc < f->min_args) + pperror("too few function arguments passed to '%s'", + name); + + if (argc > f->max_args) + pperror("too many function arguments passed to '%s'", + name); + + return f->func(argc, argv); + } + + return NULL; +} + +/* + * Variables (and user-defined functions) + */ +static LIST_HEAD(variable_list); + +struct variable { + char *name; + char *value; + enum variable_flavor flavor; + int exp_count; + struct list_head node; +}; + +static struct variable *variable_lookup(const char *name) +{ + struct variable *v; + + list_for_each_entry(v, &variable_list, node) { + if (!strcmp(name, v->name)) + return v; + } + + return NULL; +} + +static char *variable_expand(const char *name, int argc, char *argv[]) +{ + struct variable *v; + char *res; + + v = variable_lookup(name); + if (!v) + return NULL; + + if (argc == 0 && v->exp_count) + pperror("Recursive variable '%s' references itself (eventually)", + name); + + if (v->exp_count > 1000) + pperror("Too deep recursive expansion"); + + v->exp_count++; + + if (v->flavor == VAR_RECURSIVE) + res = expand_string_with_args(v->value, argc, argv); + else + res = xstrdup(v->value); + + v->exp_count--; + + return res; +} + +void variable_add(const char *name, const char *value, + enum variable_flavor flavor) +{ + struct variable *v; + char *new_value; + bool append = false; + + v = variable_lookup(name); + if (v) { + /* For defined variables, += inherits the existing flavor */ + if (flavor == VAR_APPEND) { + flavor = v->flavor; + append = true; + } else { + free(v->value); + } + } else { + /* For undefined variables, += assumes the recursive flavor */ + if (flavor == VAR_APPEND) + flavor = VAR_RECURSIVE; + + v = xmalloc(sizeof(*v)); + v->name = xstrdup(name); + v->exp_count = 0; + list_add_tail(&v->node, &variable_list); + } + + v->flavor = flavor; + + if (flavor == VAR_SIMPLE) + new_value = expand_string(value); + else + new_value = xstrdup(value); + + if (append) { + v->value = xrealloc(v->value, + strlen(v->value) + strlen(new_value) + 2); + strcat(v->value, " "); + strcat(v->value, new_value); + free(new_value); + } else { + v->value = new_value; + } +} + +static void variable_del(struct variable *v) +{ + list_del(&v->node); + free(v->name); + free(v->value); + free(v); +} + +void variable_all_del(void) +{ + struct variable *v, *tmp; + + list_for_each_entry_safe(v, tmp, &variable_list, node) + variable_del(v); +} + +/* + * Evaluate a clause with arguments. argc/argv are arguments from the upper + * function call. + * + * Returned string must be freed when done + */ +static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) +{ + char *tmp, *name, *res, *endptr, *prev, *p; + int new_argc = 0; + char *new_argv[FUNCTION_MAX_ARGS]; + int nest = 0; + int i; + unsigned long n; + + tmp = xstrndup(str, len); + + /* + * If variable name is '1', '2', etc. It is generally an argument + * from a user-function call (i.e. local-scope variable). If not + * available, then look-up global-scope variables. + */ + n = strtoul(tmp, &endptr, 10); + if (!*endptr && n > 0 && n <= argc) { + res = xstrdup(argv[n - 1]); + goto free_tmp; + } + + prev = p = tmp; + + /* + * Split into tokens + * The function name and arguments are separated by a comma. + * For example, if the function call is like this: + * $(foo,$(x),$(y)) + * + * The input string for this helper should be: + * foo,$(x),$(y) + * + * and split into: + * new_argv[0] = 'foo' + * new_argv[1] = '$(x)' + * new_argv[2] = '$(y)' + */ + while (*p) { + if (nest == 0 && *p == ',') { + *p = 0; + if (new_argc >= FUNCTION_MAX_ARGS) + pperror("too many function arguments"); + new_argv[new_argc++] = prev; + prev = p + 1; + } else if (*p == '(') { + nest++; + } else if (*p == ')') { + nest--; + } + + p++; + } + new_argv[new_argc++] = prev; + + /* + * Shift arguments + * new_argv[0] represents a function name or a variable name. Put it + * into 'name', then shift the rest of the arguments. This simplifies + * 'const' handling. + */ + name = expand_string_with_args(new_argv[0], argc, argv); + new_argc--; + for (i = 0; i < new_argc; i++) + new_argv[i] = expand_string_with_args(new_argv[i + 1], + argc, argv); + + /* Search for variables */ + res = variable_expand(name, new_argc, new_argv); + if (res) + goto free; + + /* Look for built-in functions */ + res = function_expand(name, new_argc, new_argv); + if (res) + goto free; + + /* Last, try environment variable */ + if (new_argc == 0) { + res = env_expand(name); + if (res) + goto free; + } + + res = xstrdup(""); +free: + for (i = 0; i < new_argc; i++) + free(new_argv[i]); + free(name); +free_tmp: + free(tmp); + + return res; +} + +/* + * Expand a string that follows '$' + * + * For example, if the input string is + * ($(FOO)$($(BAR)))$(BAZ) + * this helper evaluates + * $($(FOO)$($(BAR))) + * and returns a new string containing the expansion (note that the string is + * recursively expanded), also advancing 'str' to point to the next character + * after the corresponding closing parenthesis, in this case, *str will be + * $(BAR) + */ +static char *expand_dollar_with_args(const char **str, int argc, char *argv[]) +{ + const char *p = *str; + const char *q; + int nest = 0; + + /* + * In Kconfig, variable/function references always start with "$(". + * Neither single-letter variables as in $A nor curly braces as in ${CC} + * are supported. '$' not followed by '(' loses its special meaning. + */ + if (*p != '(') { + *str = p; + return xstrdup("$"); + } + + p++; + q = p; + while (*q) { + if (*q == '(') { + nest++; + } else if (*q == ')') { + if (nest-- == 0) + break; + } + q++; + } + + if (!*q) + pperror("unterminated reference to '%s': missing ')'", p); + + /* Advance 'str' to after the expanded initial portion of the string */ + *str = q + 1; + + return eval_clause(p, q - p, argc, argv); +} + +char *expand_dollar(const char **str) +{ + return expand_dollar_with_args(str, 0, NULL); +} + +static char *__expand_string(const char **str, bool (*is_end)(char c), + int argc, char *argv[]) +{ + const char *in, *p; + char *expansion, *out; + size_t in_len, out_len; + + out = xmalloc(1); + *out = 0; + out_len = 1; + + p = in = *str; + + while (1) { + if (*p == '$') { + in_len = p - in; + p++; + expansion = expand_dollar_with_args(&p, argc, argv); + out_len += in_len + strlen(expansion); + out = xrealloc(out, out_len); + strncat(out, in, in_len); + strcat(out, expansion); + free(expansion); + in = p; + continue; + } + + if (is_end(*p)) + break; + + p++; + } + + in_len = p - in; + out_len += in_len; + out = xrealloc(out, out_len); + strncat(out, in, in_len); + + /* Advance 'str' to the end character */ + *str = p; + + return out; +} + +static bool is_end_of_str(char c) +{ + return !c; +} + +/* + * Expand variables and functions in the given string. Undefined variables + * expand to an empty string. + * The returned string must be freed when done. + */ +static char *expand_string_with_args(const char *in, int argc, char *argv[]) +{ + return __expand_string(&in, is_end_of_str, argc, argv); +} + +char *expand_string(const char *in) +{ + return expand_string_with_args(in, 0, NULL); +} + +static bool is_end_of_token(char c) +{ + return !(isalnum(c) || c == '_' || c == '-'); +} + +/* + * Expand variables in a token. The parsing stops when a token separater + * (in most cases, it is a whitespace) is encountered. 'str' is updated to + * point to the next character. + * + * The returned string must be freed when done. + */ +char *expand_one_token(const char **str) +{ + return __expand_string(str, is_end_of_token, 0, NULL); +} diff --git a/carl9170fw/config/symbol.c b/carl9170fw/config/symbol.c index 3c8bd9b..1f9266d 100644 --- a/carl9170fw/config/symbol.c +++ b/carl9170fw/config/symbol.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ #include @@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list; struct symbol *modules_sym; tristate modules_val; -struct expr *sym_env_list; - -static void sym_add_default(struct symbol *sym, const char *def) -{ - struct property *prop = prop_alloc(P_DEFAULT, sym); - - prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); -} - -void sym_init(void) -{ - struct symbol *sym; - struct utsname uts; - static bool inited = false; - - if (inited) - return; - inited = true; - - uname(&uts); - - sym = sym_lookup("UNAME_RELEASE", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - sym_add_default(sym, uts.release); -} - enum symbol_type sym_get_type(struct symbol *sym) { enum symbol_type type = sym->type; @@ -77,7 +50,7 @@ const char *sym_type_name(enum symbol_type type) { switch (type) { case S_BOOLEAN: - return "boolean"; + return "bool"; case S_TRISTATE: return "tristate"; case S_INT: @@ -88,8 +61,6 @@ const char *sym_type_name(enum symbol_type type) return "string"; case S_UNKNOWN: return "unknown"; - case S_OTHER: - break; } return "???"; } @@ -103,15 +74,6 @@ struct property *sym_get_choice_prop(struct symbol *sym) return NULL; } -struct property *sym_get_env_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_ENV) - return prop; - return NULL; -} - static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; @@ -124,7 +86,7 @@ static struct property *sym_get_default_prop(struct symbol *sym) return NULL; } -static struct property *sym_get_range_prop(struct symbol *sym) +struct property *sym_get_range_prop(struct symbol *sym) { struct property *prop; @@ -183,7 +145,7 @@ static void sym_validate_range(struct symbol *sym) sprintf(str, "%lld", val2); else sprintf(str, "0x%llx", val2); - sym->curr.val = strdup(str); + sym->curr.val = xstrdup(str); } static void sym_set_changed(struct symbol *sym) @@ -243,7 +205,7 @@ static void sym_calc_visibility(struct symbol *sym) tri = yes; if (sym->dir_dep.expr) tri = expr_calc_value(sym->dir_dep.expr); - if (tri == mod) + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) tri = yes; if (sym->dir_dep.tri != tri) { sym->dir_dep.tri = tri; @@ -333,6 +295,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym) return def_sym; } +static void sym_warn_unmet_dep(struct symbol *sym) +{ + struct gstr gs = str_new(); + + str_printf(&gs, + "\nWARNING: unmet direct dependencies detected for %s\n", + sym->name); + str_printf(&gs, + " Depends on [%c]: ", + sym->dir_dep.tri == mod ? 'm' : 'n'); + expr_gstr_print(sym->dir_dep.expr, &gs); + str_printf(&gs, "\n"); + + expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes, + " Selected by [y]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod, + " Selected by [m]:\n"); + + fputs(str_get(&gs), stderr); +} + void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; @@ -371,11 +354,13 @@ void sym_calc_value(struct symbol *sym) sym->curr.tri = no; return; } - if (!sym_is_choice_value(sym)) - sym->flags &= ~SYMBOL_WRITE; + sym->flags &= ~SYMBOL_WRITE; sym_calc_visibility(sym); + if (sym->visible != no) + sym->flags |= SYMBOL_WRITE; + /* set default if recursively called */ sym->curr = newval; @@ -390,7 +375,6 @@ void sym_calc_value(struct symbol *sym) /* if the symbol is visible use the user value * if available, otherwise try the default value */ - sym->flags |= SYMBOL_WRITE; if (sym_has_value(sym)) { newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible); @@ -402,9 +386,10 @@ void sym_calc_value(struct symbol *sym) if (!sym_is_choice(sym)) { prop = sym_get_default_prop(sym); if (prop) { - sym->flags |= SYMBOL_WRITE; newval.tri = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); + if (newval.tri != no) + sym->flags |= SYMBOL_WRITE; } if (sym->implied.tri != no) { sym->flags |= SYMBOL_WRITE; @@ -412,18 +397,8 @@ void sym_calc_value(struct symbol *sym) } } calc_newval: - if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { - struct expr *e; - e = expr_simplify_unmet_dep(sym->rev_dep.expr, - sym->dir_dep.expr); - fprintf(stderr, "warning: ("); - expr_fprint(e, stderr); - fprintf(stderr, ") selects %s which has unmet direct dependencies (", - sym->name); - expr_fprint(sym->dir_dep.expr, stderr); - fprintf(stderr, ")\n"); - expr_free(e); - } + if (sym->dir_dep.tri < sym->rev_dep.tri) + sym_warn_unmet_dep(sym); newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } if (newval.tri == mod && @@ -433,12 +408,9 @@ void sym_calc_value(struct symbol *sym) case S_STRING: case S_HEX: case S_INT: - if (sym->visible != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) { - newval.val = sym->def[S_DEF_USER].val; - break; - } + if (sym->visible != no && sym_has_value(sym)) { + newval.val = sym->def[S_DEF_USER].val; + break; } prop = sym_get_default_prop(sym); if (prop) { @@ -480,7 +452,7 @@ void sym_calc_value(struct symbol *sym) } } - if (sym->flags & SYMBOL_AUTO) + if (sym->flags & SYMBOL_NO_WRITE) sym->flags &= ~SYMBOL_WRITE; if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) @@ -783,7 +755,6 @@ const char *sym_get_string_default(struct symbol *sym) return str; case S_STRING: return str; - case S_OTHER: case S_UNKNOWN: break; } @@ -851,7 +822,7 @@ struct symbol *sym_lookup(const char *name, int flags) : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) return symbol; } - new_name = strdup(name); + new_name = xstrdup(name); } else { new_name = NULL; hash = 0; @@ -896,55 +867,6 @@ struct symbol *sym_find(const char *name) return symbol; } -/* - * Expand symbol's names embedded in the string given in argument. Symbols' - * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to - * the empty string. - */ -const char *sym_expand_string_value(const char *in) -{ - const char *src; - char *res; - size_t reslen; - - reslen = strlen(in) + 1; - res = xmalloc(reslen); - res[0] = '\0'; - - while ((src = strchr(in, '$'))) { - char *p, name[SYMBOL_MAXLENGTH]; - const char *symval = ""; - struct symbol *sym; - size_t newlen; - - strncat(res, in, src - in); - src++; - - p = name; - while (isalnum(*src) || *src == '_') - *p++ = *src++; - *p = '\0'; - - sym = sym_find(name); - if (sym != NULL) { - sym_calc_value(sym); - symval = sym_get_string_value(sym); - } - - newlen = strlen(res) + strlen(symval) + strlen(src) + 1; - if (newlen > reslen) { - reslen = newlen; - res = realloc(res, reslen); - } - - strcat(res, symval); - in = src; - } - strcat(res, in); - - return res; -} - const char *sym_escape_string_value(const char *in) { const char *p; @@ -1086,7 +1008,7 @@ static struct dep_stack { struct dep_stack *prev, *next; struct symbol *sym; struct property *prop; - struct expr *expr; + struct expr **expr; } *check_top; static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) @@ -1150,37 +1072,52 @@ static void sym_check_print_recursive(struct symbol *last_sym) if (stack->sym == last_sym) fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", prop->file->name, prop->lineno); - fprintf(stderr, "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n"); - fprintf(stderr, "subsection \"Kconfig recursive dependency limitations\"\n"); - if (stack->expr) { - fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, + + if (sym_is_choice(sym)) { + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", + menu->file->name, menu->lineno, sym->name ? sym->name : "", - prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); - } else if (stack->prop) { + } else if (sym_is_choice_value(sym)) { + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (stack->expr == &sym->dir_dep.expr) { fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice(sym)) { - fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, + } else if (stack->expr == &sym->rev_dep.expr) { + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + prop->file->name, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice_value(sym)) { - fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, + } else if (stack->expr == &sym->implied.expr) { + fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (stack->expr) { + fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", + prop->file->name, prop->lineno, sym->name ? sym->name : "", + prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); } else { - fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "", + prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); } } + fprintf(stderr, + "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n" + "subsection \"Kconfig recursive dependency limitations\"\n" + "\n"); + if (check_top == &cv_stack) dep_stack_remove(); } @@ -1215,7 +1152,7 @@ static struct symbol *sym_check_expr_deps(struct expr *e) default: break; } - printf("Oops! How to check %d?\n", e->type); + fprintf(stderr, "Oops! How to check %d?\n", e->type); return NULL; } @@ -1228,12 +1165,26 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) dep_stack_insert(&stack, sym); + stack.expr = &sym->dir_dep.expr; + sym2 = sym_check_expr_deps(sym->dir_dep.expr); + if (sym2) + goto out; + + stack.expr = &sym->rev_dep.expr; sym2 = sym_check_expr_deps(sym->rev_dep.expr); if (sym2) goto out; + stack.expr = &sym->implied.expr; + sym2 = sym_check_expr_deps(sym->implied.expr); + if (sym2) + goto out; + + stack.expr = NULL; + for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT) + if (prop->type == P_CHOICE || prop->type == P_SELECT || + prop->type == P_IMPLY) continue; stack.prop = prop; sym2 = sym_check_expr_deps(prop->visible.expr); @@ -1241,7 +1192,7 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) break; if (prop->type != P_DEFAULT || sym_is_choice(sym)) continue; - stack.expr = prop->expr; + stack.expr = &prop->expr; sym2 = sym_check_expr_deps(prop->expr); if (sym2) break; @@ -1319,9 +1270,6 @@ struct symbol *sym_check_deps(struct symbol *sym) sym->flags &= ~SYMBOL_CHECK; } - if (sym2 && sym2 == sym) - sym2 = NULL; - return sym2; } @@ -1360,8 +1308,6 @@ const char *prop_get_type_name(enum prop_type type) switch (type) { case P_PROMPT: return "prompt"; - case P_ENV: - return "env"; case P_COMMENT: return "comment"; case P_MENU: @@ -1383,32 +1329,3 @@ const char *prop_get_type_name(enum prop_type type) } return "unknown"; } - -static void prop_add_env(const char *env) -{ - struct symbol *sym, *sym2; - struct property *prop; - char *p; - - sym = current_entry->sym; - sym->flags |= SYMBOL_AUTO; - for_all_properties(sym, prop, P_ENV) { - sym2 = prop_get_symbol(prop); - if (strcmp(sym2->name, env)) - menu_warn(current_entry, "redefining environment symbol from %s", - sym2->name); - return; - } - - prop = prop_alloc(P_ENV, sym); - prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); - - sym_env_list = expr_alloc_one(E_LIST, sym_env_list); - sym_env_list->right.sym = sym; - - p = getenv(env); - if (p) - sym_add_default(sym, p); - else - menu_warn(current_entry, "environment variable %s undefined", env); -} diff --git a/carl9170fw/config/util.c b/carl9170fw/config/util.c index 0e76042..2958539 100644 --- a/carl9170fw/config/util.c +++ b/carl9170fw/config/util.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002-2005 Roman Zippel * Copyright (C) 2002-2005 Sam Ravnborg - * - * Released under the terms of the GNU GPL v2.0. */ #include @@ -14,69 +13,21 @@ struct file *file_lookup(const char *name) { struct file *file; - const char *file_name = sym_expand_string_value(name); for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) { - free((void *)file_name); return file; } } file = xmalloc(sizeof(*file)); memset(file, 0, sizeof(*file)); - file->name = file_name; + file->name = xstrdup(name); file->next = file_list; file_list = file; return file; } -/* write a dependency file as used by kbuild to track dependencies */ -int file_write_dep(const char *name) -{ - struct symbol *sym, *env_sym; - struct expr *e; - struct file *file; - FILE *out; - - if (!name) - name = ".kconfig.d"; - out = fopen("..config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); - } - fprintf(out, "\n%s: \\\n" - "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - - expr_list_for_each_sym(sym_env_list, e, sym) { - struct property *prop; - const char *value; - - prop = sym_get_env_prop(sym); - env_sym = prop_get_symbol(prop); - if (!env_sym) - continue; - value = getenv(env_sym->name); - if (!value) - value = ""; - fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); - fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); - fprintf(out, "endif\n"); - } - - fprintf(out, "\n$(deps_config): ;\n"); - fclose(out); - rename("..config.tmp", name); - return 0; -} - - /* Allocate initial growable string */ struct gstr str_new(void) { @@ -104,7 +55,7 @@ void str_append(struct gstr *gs, const char *s) if (s) { l = strlen(gs->s) + strlen(s) + 1; if (l > gs->len) { - gs->s = realloc(gs->s, l); + gs->s = xrealloc(gs->s, l); gs->len = l; } strcat(gs->s, s); @@ -145,3 +96,34 @@ void *xcalloc(size_t nmemb, size_t size) fprintf(stderr, "Out of memory.\n"); exit(1); } + +void *xrealloc(void *p, size_t size) +{ + p = realloc(p, size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + +char *xstrdup(const char *s) +{ + char *p; + + p = strdup(s); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + +char *xstrndup(const char *s, size_t n) +{ + char *p; + + p = strndup(s, n); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} diff --git a/carl9170fw/config/zconf.l b/carl9170fw/config/zconf.l index 9720530..c52cce8 100644 --- a/carl9170fw/config/zconf.l +++ b/carl9170fw/config/zconf.l @@ -1,13 +1,13 @@ -%option nostdinit noyywrap never-interactive full ecs -%option 8bit nodefault perf-report perf-report -%option noinput -%x COMMAND HELP STRING PARAM -%{ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ +%option nostdinit noyywrap never-interactive full ecs +%option 8bit nodefault yylineno +%x ASSIGN_VAL HELP STRING +%{ +#include #include #include #include @@ -15,6 +15,9 @@ #include #include "lkc.h" +#include "zconf.tab.h" + +#define YY_DECL static int yylex1(void) #define START_STRSIZE 16 @@ -23,6 +26,8 @@ static struct { int lineno; } current_pos; +static int prev_prev_token = T_EOL; +static int prev_token = T_EOL; static char *text; static int text_size, text_asize; @@ -35,6 +40,8 @@ struct buffer *current_buf; static int last_ts, first_ts; +static char *expand_token(const char *in, size_t n); +static void append_expanded_string(const char *in); static void zconf_endhelp(void); static void zconf_endfile(void); @@ -52,7 +59,7 @@ static void append_string(const char *str, int size) if (new_size > text_asize) { new_size += START_STRSIZE - 1; new_size &= -START_STRSIZE; - text = realloc(text, new_size); + text = xrealloc(text, new_size); text_asize = new_size; } memcpy(text + text_size, str, size); @@ -71,7 +78,7 @@ static void warn_ignored_character(char chr) { fprintf(stderr, "%s:%d:warning: ignoring unsupported character '%c'\n", - zconf_curname(), zconf_lineno(), chr); + current_file->name, yylineno, chr); } %} @@ -81,116 +88,113 @@ n [A-Za-z0-9_-] int str = 0; int ts, i; -[ \t]*#.*\n | -[ \t]*\n { - current_file->lineno++; - return T_EOL; -} -[ \t]*#.* - - -[ \t]+ { - BEGIN(COMMAND); -} - -. { - unput(yytext[0]); - BEGIN(COMMAND); -} - - -{ - {n}+ { - const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); - BEGIN(PARAM); - current_pos.file = current_file; - current_pos.lineno = current_file->lineno; - if (id && id->flags & TF_COMMAND) { - zconflval.id = id; - return id->token; - } - alloc_string(yytext, yyleng); - zconflval.string = text; - return T_WORD; - } - . warn_ignored_character(*yytext); - \n { - BEGIN(INITIAL); - current_file->lineno++; - return T_EOL; - } -} +#.* /* ignore comment */ +[ \t]* /* whitespaces */ +\\\n /* escaped new line */ +\n return T_EOL; +"allnoconfig_y" return T_ALLNOCONFIG_Y; +"bool" return T_BOOL; +"choice" return T_CHOICE; +"comment" return T_COMMENT; +"config" return T_CONFIG; +"def_bool" return T_DEF_BOOL; +"def_tristate" return T_DEF_TRISTATE; +"default" return T_DEFAULT; +"defconfig_list" return T_DEFCONFIG_LIST; +"depends" return T_DEPENDS; +"endchoice" return T_ENDCHOICE; +"endif" return T_ENDIF; +"endmenu" return T_ENDMENU; +"help"|"---help---" return T_HELP; +"hex" return T_HEX; +"if" return T_IF; +"imply" return T_IMPLY; +"int" return T_INT; +"mainmenu" return T_MAINMENU; +"menu" return T_MENU; +"menuconfig" return T_MENUCONFIG; +"modules" return T_MODULES; +"on" return T_ON; +"option" return T_OPTION; +"optional" return T_OPTIONAL; +"prompt" return T_PROMPT; +"range" return T_RANGE; +"select" return T_SELECT; +"source" return T_SOURCE; +"string" return T_STRING; +"tristate" return T_TRISTATE; +"visible" return T_VISIBLE; +"||" return T_OR; +"&&" return T_AND; +"=" return T_EQUAL; +"!=" return T_UNEQUAL; +"<" return T_LESS; +"<=" return T_LESS_EQUAL; +">" return T_GREATER; +">=" return T_GREATER_EQUAL; +"!" return T_NOT; +"(" return T_OPEN_PAREN; +")" return T_CLOSE_PAREN; +":=" return T_COLON_EQUAL; +"+=" return T_PLUS_EQUAL; +\"|\' { + str = yytext[0]; + new_string(); + BEGIN(STRING); + } +{n}+ { + alloc_string(yytext, yyleng); + yylval.string = text; + return T_WORD; + } +({n}|$)+ { + /* this token includes at least one '$' */ + yylval.string = expand_token(yytext, yyleng); + if (strlen(yylval.string)) + return T_WORD; + free(yylval.string); + } +. warn_ignored_character(*yytext); -{ - "&&" return T_AND; - "||" return T_OR; - "(" return T_OPEN_PAREN; - ")" return T_CLOSE_PAREN; - "!" return T_NOT; - "=" return T_EQUAL; - "!=" return T_UNEQUAL; - "<=" return T_LESS_EQUAL; - ">=" return T_GREATER_EQUAL; - "<" return T_LESS; - ">" return T_GREATER; - \"|\' { - str = yytext[0]; - new_string(); - BEGIN(STRING); - } - \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; - ({n}|[/.])+ { - const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); - if (id && id->flags & TF_PARAM) { - zconflval.id = id; - return id->token; - } +{ + [^[:blank:]\n]+.* { alloc_string(yytext, yyleng); - zconflval.string = text; - return T_WORD; - } - #.* /* comment */ - \\\n current_file->lineno++; - [[:blank:]]+ - . warn_ignored_character(*yytext); - <> { - BEGIN(INITIAL); + yylval.string = text; + return T_ASSIGN_VAL; } + \n { BEGIN(INITIAL); return T_EOL; } + . } { - [^'"\\\n]+/\n { - append_string(yytext, yyleng); - zconflval.string = text; - return T_WORD_QUOTE; - } - [^'"\\\n]+ { + "$".* append_expanded_string(yytext); + [^$'"\\\n]+ { append_string(yytext, yyleng); } - \\.?/\n { - append_string(yytext + 1, yyleng - 1); - zconflval.string = text; - return T_WORD_QUOTE; - } \\.? { append_string(yytext + 1, yyleng - 1); } \'|\" { if (str == yytext[0]) { - BEGIN(PARAM); - zconflval.string = text; + BEGIN(INITIAL); + yylval.string = text; return T_WORD_QUOTE; } else append_string(yytext, 1); } \n { - printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); - current_file->lineno++; + fprintf(stderr, + "%s:%d:warning: multi-line strings not supported\n", + zconf_curname(), zconf_lineno()); + unput('\n'); BEGIN(INITIAL); - return T_EOL; + yylval.string = text; + return T_WORD_QUOTE; } <> { BEGIN(INITIAL); + yylval.string = text; + return T_WORD_QUOTE; } } @@ -218,12 +222,10 @@ n [A-Za-z0-9_-] } } [ \t]*\n/[^ \t\n] { - current_file->lineno++; zconf_endhelp(); return T_HELPTEXT; } [ \t]*\n { - current_file->lineno++; append_string("\n", 1); } [^ \t\n].* { @@ -243,6 +245,12 @@ n [A-Za-z0-9_-] } <> { + BEGIN(INITIAL); + + if (prev_token != T_EOL && prev_token != T_HELPTEXT) + fprintf(stderr, "%s:%d:warning: no new line at end of file\n", + current_file->name, yylineno); + if (current_file) { zconf_endfile(); return T_EOL; @@ -252,6 +260,93 @@ n [A-Za-z0-9_-] } %% + +/* second stage lexer */ +int yylex(void) +{ + int token; + +repeat: + token = yylex1(); + + if (prev_token == T_EOL || prev_token == T_HELPTEXT) { + if (token == T_EOL) { + /* Do not pass unneeded T_EOL to the parser. */ + goto repeat; + } else { + /* + * For the parser, update file/lineno at the first token + * of each statement. Generally, \n is a statement + * terminator in Kconfig, but it is not always true + * because \n could be escaped by a backslash. + */ + current_pos.file = current_file; + current_pos.lineno = yylineno; + } + } + + if (prev_prev_token == T_EOL && prev_token == T_WORD && + (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL)) + BEGIN(ASSIGN_VAL); + + prev_prev_token = prev_token; + prev_token = token; + + return token; +} + +static char *expand_token(const char *in, size_t n) +{ + char *out; + int c; + char c2; + const char *rest, *end; + + new_string(); + append_string(in, n); + + /* get the whole line because we do not know the end of token. */ + while ((c = input()) != EOF) { + if (c == '\n') { + unput(c); + break; + } + c2 = c; + append_string(&c2, 1); + } + + rest = text; + out = expand_one_token(&rest); + + /* push back unused characters to the input stream */ + end = rest + strlen(rest); + while (end > rest) + unput(*--end); + + free(text); + + return out; +} + +static void append_expanded_string(const char *str) +{ + const char *end; + char *res; + + str++; + + res = expand_dollar(&str); + + /* push back unused characters to the input stream */ + end = str + strlen(str); + while (end > str) + unput(*--end); + + append_string(res, strlen(res)); + + free(res); +} + void zconf_starthelp(void) { new_string(); @@ -261,7 +356,7 @@ void zconf_starthelp(void) static void zconf_endhelp(void) { - zconflval.string = text; + yylval.string = text; BEGIN(INITIAL); } @@ -294,7 +389,7 @@ void zconf_initscan(const char *name) { yyin = zconf_fopen(name); if (!yyin) { - printf("can't find file %s\n", name); + fprintf(stderr, "can't find file %s\n", name); exit(1); } @@ -302,7 +397,7 @@ void zconf_initscan(const char *name) memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); - current_file->lineno = 1; + yylineno = 1; } void zconf_nextfile(const char *name) @@ -315,35 +410,34 @@ void zconf_nextfile(const char *name) current_buf->state = YY_CURRENT_BUFFER; yyin = zconf_fopen(file->name); if (!yyin) { - printf("%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), file->name); + fprintf(stderr, "%s:%d: can't open file \"%s\"\n", + zconf_curname(), zconf_lineno(), file->name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; - for (iter = current_file->parent; iter; iter = iter->parent ) { - if (!strcmp(current_file->name,iter->name) ) { - printf("%s:%d: recursive inclusion detected. " - "Inclusion path:\n current file : '%s'\n", - zconf_curname(), zconf_lineno(), - zconf_curname()); - iter = current_file->parent; - while (iter && \ - strcmp(iter->name,current_file->name)) { - printf(" included from: '%s:%d'\n", - iter->name, iter->lineno-1); + current_file->lineno = yylineno; + file->parent = current_file; + + for (iter = current_file; iter; iter = iter->parent) { + if (!strcmp(iter->name, file->name)) { + fprintf(stderr, + "Recursive inclusion detected.\n" + "Inclusion path:\n" + " current file : %s\n", file->name); + iter = file; + do { iter = iter->parent; - } - if (iter) - printf(" included from: '%s:%d'\n", - iter->name, iter->lineno+1); + fprintf(stderr, " included from: %s:%d\n", + iter->name, iter->lineno - 1); + } while (strcmp(iter->name, file->name)); exit(1); } } - file->lineno = 1; - file->parent = current_file; + + yylineno = 1; current_file = file; } @@ -352,6 +446,8 @@ static void zconf_endfile(void) struct buffer *parent; current_file = current_file->parent; + if (current_file) + yylineno = current_file->lineno; parent = current_buf->parent; if (parent) { diff --git a/carl9170fw/config/zconf.y b/carl9170fw/config/zconf.y index 79c4f04..60936c7 100644 --- a/carl9170fw/config/zconf.y +++ b/carl9170fw/config/zconf.y @@ -1,8 +1,8 @@ -%{ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. */ +%{ #include #include @@ -20,63 +20,69 @@ int cdebug = PRINTD; -extern int zconflex(void); +static void yyerror(const char *err); static void zconfprint(const char *err, ...); static void zconf_error(const char *err, ...); -static void zconferror(const char *err); -static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); +static bool zconf_endtoken(const char *tokenname, + const char *expected_tokenname); struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; %} -%expect 32 %union { char *string; - struct file *file; struct symbol *symbol; struct expr *expr; struct menu *menu; - const struct kconf_id *id; + enum symbol_type type; + enum variable_flavor flavor; } -%token T_MAINMENU -%token T_MENU -%token T_ENDMENU -%token T_SOURCE -%token T_CHOICE -%token T_ENDCHOICE -%token T_COMMENT -%token T_CONFIG -%token T_MENUCONFIG -%token T_HELP %token T_HELPTEXT -%token T_IF -%token T_ENDIF -%token T_DEPENDS -%token T_OPTIONAL -%token T_PROMPT -%token T_TYPE -%token T_DEFAULT -%token T_SELECT -%token T_IMPLY -%token T_RANGE -%token T_VISIBLE -%token T_OPTION -%token T_ON %token T_WORD %token T_WORD_QUOTE -%token T_UNEQUAL -%token T_LESS -%token T_LESS_EQUAL -%token T_GREATER -%token T_GREATER_EQUAL +%token T_ALLNOCONFIG_Y +%token T_BOOL +%token T_CHOICE %token T_CLOSE_PAREN +%token T_COLON_EQUAL +%token T_COMMENT +%token T_CONFIG +%token T_DEFAULT +%token T_DEFCONFIG_LIST +%token T_DEF_BOOL +%token T_DEF_TRISTATE +%token T_DEPENDS +%token T_ENDCHOICE +%token T_ENDIF +%token T_ENDMENU +%token T_HELP +%token T_HEX +%token T_IF +%token T_IMPLY +%token T_INT +%token T_MAINMENU +%token T_MENU +%token T_MENUCONFIG +%token T_MODULES +%token T_ON %token T_OPEN_PAREN +%token T_OPTION +%token T_OPTIONAL +%token T_PLUS_EQUAL +%token T_PROMPT +%token T_RANGE +%token T_SELECT +%token T_SOURCE +%token T_STRING +%token T_TRISTATE +%token T_VISIBLE %token T_EOL +%token T_ASSIGN_VAL %left T_OR %left T_AND @@ -85,13 +91,15 @@ static struct menu *current_menu, *current_entry; %nonassoc T_NOT %type prompt +%type nonconst_symbol %type symbol +%type type logic_type default %type expr %type if_expr -%type end -%type option_name +%type end %type if_entry menu_entry choice_entry -%type symbol_option_arg word_opt +%type word_opt assign_val +%type assign_op %destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", @@ -100,71 +108,53 @@ static struct menu *current_menu, *current_entry; menu_end_menu(); } if_entry menu_entry choice_entry -%{ -/* Include zconf_id.c here so it can see the token constants. */ -#include "kconf_id.c" -%} - %% -input: nl start | start; +input: mainmenu_stmt stmt_list | stmt_list; -start: mainmenu_stmt stmt_list | stmt_list; +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt T_EOL +{ + menu_add_prompt(P_MENU, $2, NULL); +}; stmt_list: /* empty */ | stmt_list common_stmt | stmt_list choice_stmt | stmt_list menu_stmt - | stmt_list end { zconf_error("unexpected end statement"); } | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } - | stmt_list option_name error T_EOL -{ - zconf_error("unexpected option \"%s\"", $2->name); -} | stmt_list error T_EOL { zconf_error("invalid statement"); } ; -option_name: - T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_IMPLY | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE -; - common_stmt: - T_EOL - | if_stmt + if_stmt | comment_stmt | config_stmt | menuconfig_stmt | source_stmt + | assignment_stmt ; -option_error: - T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } - | error T_EOL { zconf_error("invalid option"); } -; - - /* config/menuconfig entry */ -config_entry_start: T_CONFIG T_WORD T_EOL +config_entry_start: T_CONFIG nonconst_symbol T_EOL { - struct symbol *sym = sym_lookup($2, 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); + $2->flags |= SYMBOL_OPTIONAL; + menu_add_entry($2); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name); }; config_stmt: config_entry_start config_option_list { - menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); }; -menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL { - struct symbol *sym = sym_lookup($2, 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); + $2->flags |= SYMBOL_OPTIONAL; + menu_add_entry($2); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name); }; menuconfig_stmt: menuconfig_entry_start config_option_list @@ -173,26 +163,22 @@ menuconfig_stmt: menuconfig_entry_start config_option_list current_entry->prompt->type = P_MENU; else zconfprint("warning: menuconfig statement without prompt"); - menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); }; config_option_list: /* empty */ | config_option_list config_option - | config_option_list symbol_option | config_option_list depends | config_option_list help - | config_option_list option_error - | config_option_list T_EOL ; -config_option: T_TYPE prompt_stmt_opt T_EOL +config_option: type prompt_stmt_opt T_EOL { - menu_set_type($1->stype); + menu_set_type($1); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), - $1->stype); + $1); }; config_option: T_PROMPT prompt if_expr T_EOL @@ -201,25 +187,25 @@ config_option: T_PROMPT prompt if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; -config_option: T_DEFAULT expr if_expr T_EOL +config_option: default expr if_expr T_EOL { menu_add_expr(P_DEFAULT, $2, $3); - if ($1->stype != S_UNKNOWN) - menu_set_type($1->stype); + if ($1 != S_UNKNOWN) + menu_set_type($1); printd(DEBUG_PARSE, "%s:%d:default(%u)\n", zconf_curname(), zconf_lineno(), - $1->stype); + $1); }; -config_option: T_SELECT T_WORD if_expr T_EOL +config_option: T_SELECT nonconst_symbol if_expr T_EOL { - menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + menu_add_symbol(P_SELECT, $2, $3); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); }; -config_option: T_IMPLY T_WORD if_expr T_EOL +config_option: T_IMPLY nonconst_symbol if_expr T_EOL { - menu_add_symbol(P_IMPLY, sym_lookup($2, 0), $3); + menu_add_symbol(P_IMPLY, $2, $3); printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno()); }; @@ -229,34 +215,30 @@ config_option: T_RANGE symbol symbol if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); }; -symbol_option: T_OPTION symbol_option_list T_EOL -; +config_option: T_OPTION T_MODULES T_EOL +{ + menu_add_option_modules(); +}; -symbol_option_list: - /* empty */ - | symbol_option_list T_WORD symbol_option_arg +config_option: T_OPTION T_DEFCONFIG_LIST T_EOL { - const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); - if (id && id->flags & TF_OPTION) - menu_add_option(id->token, $3); - else - zconfprint("warning: ignoring unknown option %s", $2); - free($2); + menu_add_option_defconfig_list(); }; -symbol_option_arg: - /* empty */ { $$ = NULL; } - | T_EQUAL prompt { $$ = $2; } -; +config_option: T_OPTION T_ALLNOCONFIG_Y T_EOL +{ + menu_add_option_allnoconfig_y(); +}; /* choice entry */ choice: T_CHOICE word_opt T_EOL { struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); - sym->flags |= SYMBOL_AUTO; + sym->flags |= SYMBOL_NO_WRITE; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); + free($2); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); }; @@ -267,7 +249,7 @@ choice_entry: choice choice_option_list choice_end: end { - if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + if (zconf_endtoken($1, "choice")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); } @@ -281,8 +263,6 @@ choice_option_list: | choice_option_list choice_option | choice_option_list depends | choice_option_list help - | choice_option_list T_EOL - | choice_option_list option_error ; choice_option: T_PROMPT prompt if_expr T_EOL @@ -291,15 +271,11 @@ choice_option: T_PROMPT prompt if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; -choice_option: T_TYPE prompt_stmt_opt T_EOL +choice_option: logic_type prompt_stmt_opt T_EOL { - if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { - menu_set_type($1->stype); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - $1->stype); - } else - YYERROR; + menu_set_type($1); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), $1); }; choice_option: T_OPTIONAL T_EOL @@ -308,16 +284,28 @@ choice_option: T_OPTIONAL T_EOL printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); }; -choice_option: T_DEFAULT T_WORD if_expr T_EOL +choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL { - if ($1->stype == S_UNKNOWN) { - menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); - printd(DEBUG_PARSE, "%s:%d:default\n", - zconf_curname(), zconf_lineno()); - } else - YYERROR; + menu_add_symbol(P_DEFAULT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); }; +type: + logic_type + | T_INT { $$ = S_INT; } + | T_HEX { $$ = S_HEX; } + | T_STRING { $$ = S_STRING; } + +logic_type: + T_BOOL { $$ = S_BOOLEAN; } + | T_TRISTATE { $$ = S_TRISTATE; } + +default: + T_DEFAULT { $$ = S_UNKNOWN; } + | T_DEF_BOOL { $$ = S_BOOLEAN; } + | T_DEF_TRISTATE { $$ = S_TRISTATE; } + choice_block: /* empty */ | choice_block common_stmt @@ -325,7 +313,7 @@ choice_block: /* if entry */ -if_entry: T_IF expr nl +if_entry: T_IF expr T_EOL { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); @@ -335,29 +323,15 @@ if_entry: T_IF expr nl if_end: end { - if (zconf_endtoken($1, T_IF, T_ENDIF)) { + if (zconf_endtoken($1, "if")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); } }; -if_stmt: if_entry if_block if_end +if_stmt: if_entry stmt_list if_end ; -if_block: - /* empty */ - | if_block common_stmt - | if_block menu_stmt - | if_block choice_stmt -; - -/* mainmenu entry */ - -mainmenu_stmt: T_MAINMENU prompt nl -{ - menu_add_prompt(P_MENU, $2, NULL); -}; - /* menu entry */ menu: T_MENU prompt T_EOL @@ -367,33 +341,33 @@ menu: T_MENU prompt T_EOL printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; -menu_entry: menu visibility_list depends_list +menu_entry: menu menu_option_list { $$ = menu_add_menu(); }; menu_end: end { - if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + if (zconf_endtoken($1, "menu")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); } }; -menu_stmt: menu_entry menu_block menu_end +menu_stmt: menu_entry stmt_list menu_end ; -menu_block: +menu_option_list: /* empty */ - | menu_block common_stmt - | menu_block menu_stmt - | menu_block choice_stmt + | menu_option_list visible + | menu_option_list depends ; source_stmt: T_SOURCE prompt T_EOL { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); zconf_nextfile($2); + free($2); }; /* comment entry */ @@ -405,10 +379,13 @@ comment: T_COMMENT prompt T_EOL printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); }; -comment_stmt: comment depends_list -{ - menu_end_entry(); -}; +comment_stmt: comment comment_option_list +; + +comment_option_list: + /* empty */ + | comment_option_list depends +; /* help option */ @@ -420,18 +397,22 @@ help_start: T_HELP T_EOL help: help_start T_HELPTEXT { + if (current_entry->help) { + free(current_entry->help); + zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used", + current_entry->sym->name ?: ""); + } + + /* Is the help text empty or all whitespace? */ + if ($2[strspn($2, " \f\n\r\t\v")] == '\0') + zconfprint("warning: '%s' defined with blank help text", + current_entry->sym->name ?: ""); + current_entry->help = $2; }; /* depends option */ -depends_list: - /* empty */ - | depends_list depends - | depends_list T_EOL - | depends_list option_error -; - depends: T_DEPENDS T_ON expr T_EOL { menu_add_dep($3); @@ -439,14 +420,7 @@ depends: T_DEPENDS T_ON expr T_EOL }; /* visibility option */ - -visibility_list: - /* empty */ - | visibility_list visible - | visibility_list T_EOL -; - -visible: T_VISIBLE if_expr +visible: T_VISIBLE if_expr T_EOL { menu_add_visibility($2); }; @@ -464,14 +438,9 @@ prompt: T_WORD | T_WORD_QUOTE ; -end: T_ENDMENU T_EOL { $$ = $1; } - | T_ENDCHOICE T_EOL { $$ = $1; } - | T_ENDIF T_EOL { $$ = $1; } -; - -nl: - T_EOL - | nl T_EOL +end: T_ENDMENU T_EOL { $$ = "menu"; } + | T_ENDCHOICE T_EOL { $$ = "choice"; } + | T_ENDIF T_EOL { $$ = "if"; } ; if_expr: /* empty */ { $$ = NULL; } @@ -491,13 +460,31 @@ expr: symbol { $$ = expr_alloc_symbol($1); } | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } ; -symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } +/* For symbol definitions, selects, etc., where quotes are not accepted */ +nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }; + +symbol: nonconst_symbol | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } ; word_opt: /* empty */ { $$ = NULL; } | T_WORD +/* assignment statement */ + +assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } + +assign_op: + T_EQUAL { $$ = VAR_RECURSIVE; } + | T_COLON_EQUAL { $$ = VAR_SIMPLE; } + | T_PLUS_EQUAL { $$ = VAR_APPEND; } +; + +assign_val: + /* empty */ { $$ = xstrdup(""); }; + | T_ASSIGN_VAL +; + %% void conf_parse(const char *name) @@ -507,61 +494,51 @@ void conf_parse(const char *name) zconf_initscan(name); - sym_init(); _menu_init(); - rootmenu.prompt = menu_add_prompt(P_MENU, "CARL9170 Firmware Configuration", NULL); if (getenv("ZCONF_DEBUG")) - zconfdebug = 1; - zconfparse(); - if (zconfnerrs) + yydebug = 1; + yyparse(); + + /* Variables are expanded in the parse phase. We can free them here. */ + variable_all_del(); + + if (yynerrs) exit(1); if (!modules_sym) modules_sym = sym_find( "n" ); - rootmenu.prompt->text = _(rootmenu.prompt->text); - rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + if (!menu_has_prompt(&rootmenu)) { + current_entry = &rootmenu; + menu_add_prompt(P_MENU, "Main menu", NULL); + } menu_finalize(&rootmenu); for_all_symbols(i, sym) { if (sym_check_deps(sym)) - zconfnerrs++; + yynerrs++; } - if (zconfnerrs) + if (yynerrs) exit(1); sym_set_change_count(1); } -static const char *zconf_tokenname(int token) -{ - switch (token) { - case T_MENU: return "menu"; - case T_ENDMENU: return "endmenu"; - case T_CHOICE: return "choice"; - case T_ENDCHOICE: return "endchoice"; - case T_IF: return "if"; - case T_ENDIF: return "endif"; - case T_DEPENDS: return "depends"; - case T_VISIBLE: return "visible"; - } - return ""; -} - -static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +static bool zconf_endtoken(const char *tokenname, + const char *expected_tokenname) { - if (id->token != endtoken) { + if (strcmp(tokenname, expected_tokenname)) { zconf_error("unexpected '%s' within %s block", - id->name, zconf_tokenname(starttoken)); - zconfnerrs++; + tokenname, expected_tokenname); + yynerrs++; return false; } if (current_menu->file != current_file) { zconf_error("'%s' in different file than '%s'", - id->name, zconf_tokenname(starttoken)); + tokenname, expected_tokenname); fprintf(stderr, "%s:%d: location of the '%s'\n", current_menu->file->name, current_menu->lineno, - zconf_tokenname(starttoken)); - zconfnerrs++; + expected_tokenname); + yynerrs++; return false; } return true; @@ -582,7 +559,7 @@ static void zconf_error(const char *err, ...) { va_list ap; - zconfnerrs++; + yynerrs++; fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); va_start(ap, err); vfprintf(stderr, err, ap); @@ -590,7 +567,7 @@ static void zconf_error(const char *err, ...) fprintf(stderr, "\n"); } -static void zconferror(const char *err) +static void yyerror(const char *err) { fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); } @@ -623,7 +600,7 @@ static void print_symbol(FILE *out, struct menu *menu) fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: - fputs(" boolean\n", out); + fputs(" bool\n", out); break; case S_TRISTATE: fputs(" tristate\n", out); @@ -686,6 +663,10 @@ static void print_symbol(FILE *out, struct menu *menu) print_quoted_string(out, prop->text); fputc('\n', out); break; + case P_SYMBOL: + fputs( " symbol ", out); + fprintf(out, "%s\n", prop->sym->name); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -746,9 +727,5 @@ void zconfdump(FILE *out) } } -#include "zconf.lex.c" #include "util.c" -#include "confdata.c" -#include "expr.c" -#include "symbol.c" #include "menu.c" diff --git a/carl9170fw/include/linux/ieee80211.h b/carl9170fw/include/linux/ieee80211.h index 31c59ea..46ce6cf 100644 --- a/carl9170fw/include/linux/ieee80211.h +++ b/carl9170fw/include/linux/ieee80211.h @@ -897,33 +897,33 @@ struct ieee80211_mgmt { __le16 status_code; /* possibly followed by Challenge text */ u8 variable[0]; - } __packed auth; + } __packed __aligned(4) auth; struct { __le16 reason_code; - } __packed deauth; + } __packed __aligned(4) deauth; struct { __le16 capab_info; __le16 listen_interval; /* followed by SSID and Supported rates */ u8 variable[0]; - } __packed assoc_req; + } __packed __aligned(4) assoc_req; struct { __le16 capab_info; __le16 status_code; __le16 aid; /* followed by Supported rates */ u8 variable[0]; - } __packed assoc_resp, reassoc_resp; + } __packed __aligned(4) assoc_resp, reassoc_resp; struct { __le16 capab_info; __le16 listen_interval; u8 current_ap[6]; /* followed by SSID and Supported rates */ u8 variable[0]; - } __packed reassoc_req; + } __packed __aligned(4) reassoc_req; struct { __le16 reason_code; - } __packed disassoc; + } __packed __aligned(4) disassoc; struct { __le64 timestamp; __le16 beacon_int; @@ -931,11 +931,11 @@ struct ieee80211_mgmt { /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[0]; - } __packed beacon; + } __packed __aligned(4) beacon; struct { /* only variable items: SSID, Supported rates */ u8 variable[0]; - } __packed probe_req; + } __packed __aligned(4) probe_req; struct { __le64 timestamp; __le16 beacon_int; @@ -943,7 +943,7 @@ struct ieee80211_mgmt { /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params */ u8 variable[0]; - } __packed probe_resp; + } __packed __aligned(4) probe_resp; struct { u8 category; union { @@ -1041,8 +1041,8 @@ struct ieee80211_mgmt { u8 variable[0]; } __packed ftm; } u; - } __packed action; - } u; + } __packed __aligned(4) action; + } u __aligned(2); } __packed __aligned(2); /* Supported rates membership selectors */ @@ -1245,7 +1245,7 @@ struct ieee80211_bar { __u8 ta[6]; __le16 control; __le16 start_seq_num; -} __packed __aligned(4); +} __packed __aligned(2); /* 802.11 BA(R) control masks */ #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 diff --git a/carl9170fw/include/shared/wlan.h b/carl9170fw/include/shared/wlan.h index 9c6b7ff..117f005 100644 --- a/carl9170fw/include/shared/wlan.h +++ b/carl9170fw/include/shared/wlan.h @@ -273,7 +273,7 @@ struct ar9170_tx_frame { struct ieee80211_hdr i3e; u8 payload[0]; } data; -} __packed; +} __packed __aligned(4); struct carl9170_tx_superframe { struct carl9170_tx_superdesc s; diff --git a/carl9170fw/toolchain/Makefile b/carl9170fw/toolchain/Makefile index 11db906..43e546d 100644 --- a/carl9170fw/toolchain/Makefile +++ b/carl9170fw/toolchain/Makefile @@ -1,16 +1,16 @@ -BINUTILS_VER=2.31.1 +BINUTILS_VER=2.32 BINUTILS_TAR=binutils-$(BINUTILS_VER).tar.xz BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/$(BINUTILS_TAR)" -NEWLIB_VER=3.0.0 +NEWLIB_VER=3.1.0 NEWLIB_TAR=newlib-$(NEWLIB_VER).tar.gz NEWLIB_URL="ftp://sourceware.org/pub/newlib/$(NEWLIB_TAR)" -GCC_VER=8.2.0 +GCC_VER=9.1.0 GCC_TAR=gcc-$(GCC_VER).tar.xz GCC_URL="https://ftp.gnu.org/gnu/gcc/gcc-$(GCC_VER)/$(GCC_TAR)" -MPFR_VER=4.0.1 +MPFR_VER=4.0.2 MPFR_TAR=mpfr-$(MPFR_VER).tar.xz MPFR_URL="https://ftp.gnu.org/gnu/mpfr/$(MPFR_TAR)" diff --git a/carl9170fw/toolchain/SHA256SUMS b/carl9170fw/toolchain/SHA256SUMS index 1b65040..3a53959 100644 --- a/carl9170fw/toolchain/SHA256SUMS +++ b/carl9170fw/toolchain/SHA256SUMS @@ -1,16 +1,6 @@ -1cf7adf8ff4b5aa49041c8734bbcf1ad18cc4c94d0029aae0f4e48841088479a src/gcc-7.2.0.tar.xz -5b76a9b97c9464209772ed25ce55181a7bb144a66e5669aaec945aa64da3189b src/newlib-2.5.0.tar.gz -0b871e271c4c620444f8264f72143b4d224aa305306d85dd77ab8dce785b1e85 src/binutils-2.29.tar.xz 87b565e89a9a684fe4ebeeddb8399dce2599f9c9049854ca8c0dfbdea0e21912 src/gmp-6.1.2.tar.xz -617decc6ea09889fb08ede330917a00b16809b8db88c29c31bfbb49cbf88ecc3 src/mpc-1.0.3.tar.gz -7a62ac1a04408614fccdc506e4844b10cf0ad2c2b1677097f8f35d3a1344a950 src/mpfr-3.1.6.tar.xz 6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e src/mpc-1.1.0.tar.gz -fbe2cd1418b321f5c899ce4f0f0f4e73f5ecc7d02145b0e1fd096f5c3afb8a1d src/mpfr-4.0.0.tar.xz -c8566335ee74e5fcaeb8595b4ebd0400c4b043d6acb3263ecb1314f8f5501332 src/newlib-3.0.0.tar.gz -832ca6ae04636adbb430e865a1451adf6979ab44ca1c8374f61fba65645ce15c src/gcc-7.3.0.tar.xz -e7010a46969f9d3e53b650a518663f98a5dde3c3ae21b7d71e5e6803bc36b577 src/binutils-2.29.1.tar.xz -67874a60826303ee2fb6affc6dc0ddd3e749e9bfcb4c8655e3953d0458a6e16e src/mpfr-4.0.1.tar.xz -6e46b8aeae2f727a36f0bd9505e405768a72218f1796f0d09757d45209871ae6 src/binutils-2.30.tar.xz -1d1866f992626e61349a1ccd0b8d5253816222cdc13390dcfaa74b093aa2b153 src/gcc-8.1.0.tar.xz -5d20086ecf5752cc7d9134246e9588fa201740d540f7eb84d795b1f7a93bca86 src/binutils-2.31.1.tar.xz -196c3c04ba2613f893283977e6011b2345d1cd1af9abeac58e916b1aab3e0080 src/gcc-8.2.0.tar.xz \ No newline at end of file +fb4fa1cc21e9060719208300a61420e4089d6de6ef59cf533b57fe74801d102a src/newlib-3.1.0.tar.gz +1d3be708604eae0e42d578ba93b390c2a145f17743a744d8f3f8c2ad5855a38a src/mpfr-4.0.2.tar.xz +0ab6c55dd86a92ed561972ba15b9b70a8b9f75557f896446c82e8b36e473ee04 src/binutils-2.32.tar.xz +79a66834e96a6050d8fe78db2c3b32fb285b230b855d0a66288235bc04b327a0 src/gcc-9.1.0.tar.xz -- 2.25.1