summaryrefslogtreecommitdiff
path: root/scripts/kconfig
diff options
context:
space:
mode:
authorKacper <kacper@mail.openlinux.dev>2025-12-07 20:10:31 +0100
committerKacper <kacper@mail.openlinux.dev>2025-12-07 20:10:31 +0100
commitfc00c656c96528112d05cf0edf8631bd5eaea446 (patch)
treea6e0e6c588191a8bd1c64afc3b7a258e3e66c236 /scripts/kconfig
Add build system scaffolding and libc headers
Diffstat (limited to 'scripts/kconfig')
-rw-r--r--scripts/kconfig/checklist.c318
-rwxr-xr-xscripts/kconfig/confbin0 -> 185320 bytes
-rw-r--r--scripts/kconfig/conf.c869
-rw-r--r--scripts/kconfig/confdata.c1143
-rw-r--r--scripts/kconfig/dialog.h203
-rw-r--r--scripts/kconfig/expr.c1180
-rw-r--r--scripts/kconfig/expr.h328
-rw-r--r--scripts/kconfig/images.c328
-rw-r--r--scripts/kconfig/images.h33
-rw-r--r--scripts/kconfig/include/array_size.h11
-rw-r--r--scripts/kconfig/include/config/auto.conf4
-rw-r--r--scripts/kconfig/include/config/auto.conf.cmd7
-rw-r--r--scripts/kconfig/include/generated/autoconf.h4
-rw-r--r--scripts/kconfig/include/generated/rustc_cfg0
-rw-r--r--scripts/kconfig/include/hash.h28
-rw-r--r--scripts/kconfig/include/hashtable.h98
-rw-r--r--scripts/kconfig/include/list.h428
-rw-r--r--scripts/kconfig/include/list_types.h17
-rw-r--r--scripts/kconfig/include/xalloc.h53
-rw-r--r--scripts/kconfig/inputbox.c291
-rw-r--r--scripts/kconfig/internal.h27
-rw-r--r--scripts/kconfig/lexer.l461
-rw-r--r--scripts/kconfig/lexer.lex.c4216
-rw-r--r--scripts/kconfig/lkc.h138
-rw-r--r--scripts/kconfig/lkc_proto.h48
-rw-r--r--scripts/kconfig/lutil.c672
-rw-r--r--scripts/kconfig/makefile44
-rwxr-xr-xscripts/kconfig/mconfbin0 -> 224232 bytes
-rw-r--r--scripts/kconfig/mconf-cflags1
-rw-r--r--scripts/kconfig/mconf-libs1
-rw-r--r--scripts/kconfig/mconf.c940
-rw-r--r--scripts/kconfig/menu.c864
-rw-r--r--scripts/kconfig/menubox.c416
-rwxr-xr-xscripts/kconfig/merge_config.sh213
-rw-r--r--scripts/kconfig/mnconf-common.c53
-rw-r--r--scripts/kconfig/mnconf-common.h20
-rw-r--r--scripts/kconfig/parser.tab.c2645
-rw-r--r--scripts/kconfig/parser.tab.h163
-rw-r--r--scripts/kconfig/parser.y802
-rw-r--r--scripts/kconfig/preprocess.c581
-rw-r--r--scripts/kconfig/preprocess.h19
-rwxr-xr-xscripts/kconfig/streamline_config.pl716
-rw-r--r--scripts/kconfig/symbol.c1366
-rw-r--r--scripts/kconfig/textbox.c358
-rw-r--r--scripts/kconfig/util.c96
-rw-r--r--scripts/kconfig/yesno.c101
46 files changed, 20304 insertions, 0 deletions
diff --git a/scripts/kconfig/checklist.c b/scripts/kconfig/checklist.c
new file mode 100644
index 00000000..75493302
--- /dev/null
+++ b/scripts/kconfig/checklist.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * checklist.c -- implements the checklist box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+ int i;
+ char *list_item = malloc(list_width + 1);
+
+ strncpy(list_item, item_str(), list_width - item_x);
+ list_item[list_width - item_x] = '\0';
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+
+ wmove(win, choice, check_x);
+ wattrset(win, selected ? dlg.check_selected.atr
+ : dlg.check.atr);
+ if (!item_is_tag(':'))
+ wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+ wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+ mvwaddch(win, choice, item_x, list_item[0]);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ waddstr(win, list_item + 1);
+ if (selected) {
+ wmove(win, choice, check_x + 1);
+ wrefresh(win);
+ }
+ free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+ int y, int x, int height)
+{
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + choice < item_no - 1)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+}
+
+/*
+ * Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, "Select", y, x, selected == 0);
+ print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height)
+{
+ int i, x, y, box_x, box_y;
+ int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+ WINDOW *dialog, *list;
+
+ /* which item to highlight */
+ item_foreach() {
+ if (item_is_tag('X'))
+ choice = item_n();
+ if (item_is_selected()) {
+ choice = item_n();
+ break;
+ }
+ }
+
+do_resize:
+ if (getmaxy(stdscr) < (height + CHECKLIST_HEIGHT_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ max_choice = MIN(list_height, item_count());
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ list_width = width - 6;
+ box_y = height - list_height - 5;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin(dialog, list_height, list_width, y + box_y + 1,
+ x + box_x + 1);
+
+ keypad(list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ /* Find length of longest item in order to center checklist */
+ check_x = 0;
+ item_foreach()
+ check_x = MAX(check_x, strlen(item_str()) + 4);
+ check_x = MIN(check_x, list_width);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + 4;
+
+ if (choice >= list_height) {
+ scroll = choice - list_height + 1;
+ choice -= scroll;
+ }
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ print_item(list, i, i == choice);
+ }
+
+ print_arrows(dialog, choice, item_count(), scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ print_buttons(dialog, height, width, 0);
+
+ wmove(list, choice, check_x + 1);
+ wrefresh(list);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ for (i = 0; i < max_choice; i++) {
+ item_set(i + scroll);
+ if (toupper(key) == toupper(item_str()[0]))
+ break;
+ }
+
+ if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+ key == '+' || key == '-') {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (!scroll)
+ continue;
+ /* Scroll list down */
+ if (list_height > 1) {
+ /* De-highlight current first item */
+ item_set(scroll);
+ print_item(list, 0, FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+ item_set(scroll);
+ print_item(list, 0, TRUE);
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice - 1;
+ } else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+ if (scroll + choice >= item_count() - 1)
+ continue;
+ /* Scroll list up */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ item_set(scroll + max_choice - 1);
+ print_item(list,
+ max_choice - 1,
+ FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, 1);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+ item_set(scroll + max_choice - 1);
+ print_item(list, max_choice - 1, TRUE);
+
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice + 1;
+ }
+ if (i != choice) {
+ /* De-highlight current item */
+ item_set(scroll + choice);
+ print_item(list, choice, FALSE);
+ /* Highlight new item */
+ choice = i;
+ item_set(scroll + choice);
+ print_item(list, choice, TRUE);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ switch (key) {
+ case 'H':
+ case 'h':
+ case '?':
+ button = 1;
+ /* fall-through */
+ case 'S':
+ case 's':
+ case ' ':
+ case '\n':
+ item_foreach()
+ item_set_selected(0);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ delwin(list);
+ delwin(dialog);
+ return button;
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(list);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+
+ /* Now, update everything... */
+ doupdate();
+ }
+ delwin(list);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
diff --git a/scripts/kconfig/conf b/scripts/kconfig/conf
new file mode 100755
index 00000000..a4585c5e
--- /dev/null
+++ b/scripts/kconfig/conf
Binary files differ
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
new file mode 100644
index 00000000..a7b44cd8
--- /dev/null
+++ b/scripts/kconfig/conf.c
@@ -0,0 +1,869 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ syncconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ helpnewconfig,
+ olddefconfig,
+ yes2modconfig,
+ mod2yesconfig,
+ mod2noconfig,
+};
+static enum input_mode input_mode = oldaskconfig;
+static int input_mode_opt;
+static int indent = 1;
+static int tty_stdio;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+/* Helper function to facilitate fgets() by Jean Sacren. */
+static void xfgets(char *str, int size, FILE *in)
+{
+ if (!fgets(str, size, in))
+ fprintf(stderr, "\nError in reading or end of file.\n");
+
+ if (!tty_stdio)
+ printf("%s", str);
+}
+
+static void set_randconfig_seed(void)
+{
+ unsigned int seed;
+ char *env;
+ bool seed_set = false;
+
+ env = getenv("KCONFIG_SEED");
+ if (env && *env) {
+ char *endp;
+
+ seed = strtol(env, &endp, 0);
+ if (*endp == '\0')
+ seed_set = true;
+ }
+
+ if (!seed_set) {
+ struct timeval now;
+
+ /*
+ * Use microseconds derived seed, compensate for systems where it may
+ * be zero.
+ */
+ gettimeofday(&now, NULL);
+ seed = (now.tv_sec + 1) * (now.tv_usec + 1);
+ }
+
+ printf("KCONFIG_SEED=0x%X\n", seed);
+ srand(seed);
+}
+
+/**
+ * randomize_choice_values - randomize choice block
+ *
+ * @choice: menu entry for the choice
+ */
+static void randomize_choice_values(struct menu *choice)
+{
+ struct menu *menu;
+ int x;
+ int cnt = 0;
+
+ /*
+ * First, count the number of symbols to randomize. If sym_has_value()
+ * is true, it was specified by KCONFIG_ALLCONFIG. It needs to be
+ * respected.
+ */
+ menu_for_each_sub_entry(menu, choice) {
+ struct symbol *sym = menu->sym;
+
+ if (sym && !sym_has_value(sym))
+ cnt++;
+ }
+
+ while (cnt > 0) {
+ x = rand() % cnt;
+
+ menu_for_each_sub_entry(menu, choice) {
+ struct symbol *sym = menu->sym;
+
+ if (sym && !sym_has_value(sym))
+ x--;
+
+ if (x < 0) {
+ sym->def[S_DEF_USER].tri = yes;
+ sym->flags |= SYMBOL_DEF_USER;
+ /*
+ * Move the selected item to the _tail_ because
+ * this needs to have a lower priority than the
+ * user input from KCONFIG_ALLCONFIG.
+ */
+ list_move_tail(&sym->choice_link,
+ &choice->choice_members);
+
+ break;
+ }
+ }
+ cnt--;
+ }
+}
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+static void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct menu *menu;
+ int cnt;
+ /*
+ * can't go as the default in switch-case below, otherwise gcc whines
+ * about -Wmaybe-uninitialized
+ */
+ int pby = 50; /* probability of bool = y */
+ int pty = 33; /* probability of tristate = y */
+ int ptm = 33; /* probability of tristate = m */
+
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+
+ n = 0;
+ while (env && *env) {
+ char *endp;
+ int tmp = strtol(env, &endp, 10);
+
+ if (tmp >= 0 && tmp <= 100) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ env = (*endp == ':') ? endp + 1 : endp;
+ if (n >= 3)
+ break;
+ }
+ switch (n) {
+ case 1:
+ pby = p[0];
+ ptm = pby / 2;
+ pty = pby - ptm;
+ break;
+ case 2:
+ pty = p[0];
+ ptm = p[1];
+ pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0];
+ pty = p[1];
+ ptm = p[2];
+ break;
+ }
+
+ if (pty + ptm > 100) {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ }
+
+ menu_for_each_entry(menu) {
+ struct symbol *sym = menu->sym;
+ tristate val;
+
+ if (!sym || !menu->prompt || sym_has_value(sym) ||
+ (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
+ sym_is_choice_value(sym))
+ continue;
+
+ if (sym_is_choice(sym)) {
+ if (mode == def_random)
+ randomize_choice_values(menu);
+ continue;
+ }
+
+ switch (mode) {
+ case def_yes:
+ val = yes;
+ break;
+ case def_mod:
+ val = mod;
+ break;
+ case def_no:
+ val = no;
+ break;
+ case def_random:
+ val = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ val = yes;
+ else if (cnt < pty + ptm)
+ val = mod;
+ } else if (cnt < pby) {
+ val = yes;
+ }
+ break;
+ default:
+ continue;
+ }
+ sym->def[S_DEF_USER].tri = val;
+ sym->flags |= SYMBOL_DEF_USER;
+ }
+
+ sym_clear_all_valid();
+}
+
+static void conf_rewrite_tristates(tristate old_val, tristate new_val)
+{
+ struct symbol *sym;
+
+ for_all_symbols(sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changeable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ /* fall through */
+ default:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ break;
+ }
+
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (def)
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ printf("/?] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static void conf_choice(struct menu *menu)
+{
+ struct symbol *def_sym;
+ struct menu *child;
+ bool is_new = false;
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_calc_choice(menu);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s (%s)", cnt, menu_get_prompt(child),
+ child->sym->name);
+ if (!sym_has_value(child->sym)) {
+ is_new = true;
+ printf(" (NEW)");
+ }
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d?]: ", cnt);
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ choice_set_value(menu, child->sym);
+ return;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ return;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym) && sym_is_changeable(sym)) {
+ switch (input_mode) {
+ case listnewconfig:
+ if (sym->name)
+ print_symbol_for_listconfig(sym);
+ break;
+ case helpnewconfig:
+ printf("-----\n");
+ print_help(menu);
+ printf("-----\n");
+ break;
+ default:
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_menu_or_parent_menu(menu);
+ conf(rootEntry);
+ break;
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static const struct option long_opts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"silent", no_argument, NULL, 's'},
+ {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
+ {"oldconfig", no_argument, &input_mode_opt, oldconfig},
+ {"syncconfig", no_argument, &input_mode_opt, syncconfig},
+ {"defconfig", required_argument, &input_mode_opt, defconfig},
+ {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
+ {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
+ {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
+ {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
+ {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
+ {"randconfig", no_argument, &input_mode_opt, randconfig},
+ {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
+ {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
+ {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
+ {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
+ {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
+ {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+ printf("Usage: %s [options] kconfig_file\n", progname);
+ printf("\n");
+ printf("Generic options:\n");
+ printf(" -h, --help Print this message and exit.\n");
+ printf(" -s, --silent Do not print log.\n");
+ printf("\n");
+ printf("Mode options:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --helpnewconfig List new options and help text\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 <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+ printf(" --yes2modconfig Change answers from yes to mod if possible\n");
+ printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+ printf(" --mod2noconfig Change answers from mod to no if possible\n");
+ printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+ printf("\n");
+ printf("Arguments:\n");
+ printf(" kconfig_file Top-level Kconfig file.\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ int no_conf_write = 0;
+
+ tty_stdio = isatty(0) && isatty(1);
+
+ while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ conf_usage(progname);
+ exit(1);
+ break;
+ case 's':
+ conf_set_message_callback(NULL);
+ break;
+ case 0:
+ input_mode = input_mode_opt;
+ switch (input_mode) {
+ 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;
+ break;
+ case randconfig:
+ set_randconfig_seed();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (ac == optind) {
+ fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ conf_parse(av[optind]);
+ //zconfdump(stdout);
+
+ switch (input_mode) {
+ case defconfig:
+ if (conf_read(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 helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ case mod2noconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ 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",
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ 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",
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (conf_errors())
+ exit(1);
+
+ 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:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ conf_set_all_new_symbols(def_random);
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case yes2modconfig:
+ conf_rewrite_tristates(yes, mod);
+ break;
+ case mod2yesconfig:
+ conf_rewrite_tristates(mod, yes);
+ break;
+ case mod2noconfig:
+ conf_rewrite_tristates(mod, no);
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = oldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case syncconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
+ break;
+ }
+
+ if (sym_dep_errors())
+ exit(1);
+
+ if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
+ if (!no_conf_write && conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
+ exit(1);
+ }
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/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.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
new file mode 100644
index 00000000..9599a040
--- /dev/null
+++ b/scripts/kconfig/confdata.c
@@ -0,0 +1,1143 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <xalloc.h>
+#include "internal.h"
+#include "lkc.h"
+
+struct gstr autoconf_cmd;
+
+/* 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 false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (memcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * 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;
+
+ /* check overflow: prefix + name + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
+ return -1;
+
+ strcpy(depfile_path + depfile_prefix_len, name);
+
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings;
+
+bool conf_errors(void)
+{
+ if (conf_warnings)
+ return getenv("KCONFIG_WERROR");
+ return false;
+}
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *s)
+{
+ printf("#\n# ");
+ printf("%s", s);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback)(const char *s) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn)(const char *s))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+static const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static const char *conf_get_autoheader_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOHEADER");
+
+ return name ? name : "include/generated/autoconf.h";
+}
+
+static const char *conf_get_rustccfg_name(void)
+{
+ char *name = getenv("KCONFIG_RUSTCCFG");
+
+ return name ? name : "include/generated/rustc_cfg";
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_STRING:
+ /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
+ if (def != S_DEF_AUTO) {
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ conf_warning("invalid string found");
+ return 1;
+ }
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = xstrdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+/* like getline(), but the newline character is stripped away */
+static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream)
+{
+ ssize_t len;
+
+ len = getline(lineptr, n, stream);
+
+ if (len > 0 && (*lineptr)[len - 1] == '\n') {
+ len--;
+ (*lineptr)[len] = '\0';
+
+ if (len > 0 && (*lineptr)[len - 1] == '\r') {
+ len--;
+ (*lineptr)[len] = '\0';
+ }
+ }
+
+ return len;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *val;
+ struct symbol *sym;
+ int def_flags;
+ const char *warn_unknown, *sym_name;
+
+ warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ char *env;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ conf_set_changed(true);
+
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
+ return 1;
+
+ while (1) {
+ bool is_last;
+
+ while (isspace(*env))
+ env++;
+
+ if (!*env)
+ break;
+
+ p = env;
+ while (*p && !isspace(*p))
+ p++;
+
+ is_last = (*p == '\0');
+
+ *p = '\0';
+
+ name = env;
+
+ in = zconf_fopen(name);
+ if (in) {
+ conf_message("using defaults found in %s",
+ name);
+ goto load;
+ }
+
+ if (is_last)
+ break;
+
+ env = p + 1;
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(sym) {
+ sym->flags &= ~def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ if (def == S_DEF_USER) {
+ for_all_symbols(sym)
+ sym->flags &= ~SYMBOL_VALID;
+ expr_invalidate_all();
+ }
+
+ while (getline_stripped(&line, &line_asize, in) != -1) {
+ struct menu *choice;
+
+ conf_lineno++;
+
+ if (!line[0]) /* blank line */
+ continue;
+
+ if (line[0] == '#') {
+ if (line[1] != ' ')
+ continue;
+ p = line + 2;
+ if (memcmp(p, CONFIG_, strlen(CONFIG_)))
+ continue;
+ sym_name = p + strlen(CONFIG_);
+ p = strchr(sym_name, ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strcmp(p, "is not set"))
+ continue;
+
+ val = "n";
+ } else {
+ if (memcmp(line, CONFIG_, strlen(CONFIG_))) {
+ conf_warning("unexpected data: %s", line);
+ continue;
+ }
+
+ sym_name = line + strlen(CONFIG_);
+ p = strchr(sym_name, '=');
+ if (!p) {
+ conf_warning("unexpected data: %s", line);
+ continue;
+ }
+ *p = 0;
+ val = p + 1;
+ }
+
+ sym = sym_find(sym_name);
+ 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
+ * must be touched.
+ */
+ conf_touch_dep(sym_name);
+ } else {
+ if (warn_unknown)
+ conf_warning("unknown symbol: %s", sym_name);
+
+ conf_set_changed(true);
+ }
+ continue;
+ }
+
+ if (sym->flags & def_flags)
+ conf_warning("override: reassigning to symbol %s", sym->name);
+
+ if (conf_set_sym_val(sym, def, def_flags, val))
+ continue;
+
+ if (def != S_DEF_USER)
+ continue;
+
+ /*
+ * If this is a choice member, give it the highest priority.
+ * If conflicting CONFIG options are given from an input file,
+ * the last one wins.
+ */
+ choice = sym_get_choice_menu(sym);
+ if (choice)
+ list_move(&sym->choice_link, &choice->choice_members);
+ }
+ free(line);
+ fclose(in);
+
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+
+ conf_set_changed(false);
+
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
+ continue;
+ break;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_set_changed(true);
+ /* maybe print value in verbose mode... */
+ }
+
+ if (conf_warnings)
+ conf_set_changed(true);
+
+ return 0;
+}
+
+struct comment_style {
+ const char *decoration;
+ const char *prefix;
+ const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+ .decoration = "#",
+ .prefix = "#",
+ .postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+ .decoration = " *",
+ .prefix = "/*",
+ .postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
+{
+ if (!cs)
+ return;
+
+ fprintf(fp, "%s\n", cs->prefix);
+
+ fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+ cs->decoration);
+
+ fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
+
+ fprintf(fp, "%s\n", cs->postfix);
+}
+
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
+{
+ const char *p;
+ char *out;
+ size_t len;
+
+ len = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ while (1) {
+ p += strcspn(p, "\"\\");
+
+ if (p[0] == '\0')
+ break;
+
+ len++;
+ p++;
+ }
+
+ out = xmalloc(len);
+ out[0] = '\0';
+
+ strcat(out, "\"");
+
+ p = in;
+ while (1) {
+ len = strcspn(p, "\"\\");
+ strncat(out, p, len);
+ p += len;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(out, "\\");
+ strncat(out, p++, 1);
+ }
+
+ strcat(out, "\"");
+
+ return out;
+}
+
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+ bool escape_string)
+{
+ const char *val;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+ output_n != OUTPUT_N && *val == 'n') {
+ if (output_n == OUTPUT_N_AS_UNSET)
+ fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+ return;
+ }
+
+ if (sym->type == S_STRING && escape_string) {
+ escaped = escape_string_value(val);
+ val = escaped;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_NONE, false);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
+{
+ __print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *sym_suffix = "";
+ const char *val_prefix = "";
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (*val) {
+ case 'n':
+ return;
+ case 'm':
+ sym_suffix = "_MODULE";
+ /* fall through */
+ default:
+ val = "1";
+ }
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ case S_STRING:
+ escaped = escape_string_value(val);
+ val = escaped;
+ default:
+ break;
+ }
+
+ fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+ val_prefix, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *val_prefix = "";
+ char *val_prefixed = NULL;
+ size_t val_prefixed_len;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /*
+ * We do not care about disabled ones, i.e. no need for
+ * what otherwise are "comments" in other printers.
+ */
+ if (*val == 'n')
+ return;
+
+ /*
+ * To have similar functionality to the C macro `IS_ENABLED()`
+ * we provide an empty `--cfg CONFIG_X` here in both `y`
+ * and `m` cases.
+ *
+ * Then, the common `fprintf()` below will also give us
+ * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+ * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+ */
+ fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ default:
+ break;
+ }
+
+ if (strlen(val_prefix) > 0) {
+ val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
+ val_prefixed = xmalloc(val_prefixed_len);
+ snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
+ val = val_prefixed;
+ }
+
+ /* All values get escaped: the `--cfg` option only takes strings */
+ escaped = escape_string_value(val);
+ val = escaped;
+
+ fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+ free(val_prefixed);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ menu_for_each_entry(menu) {
+ struct menu *choice;
+
+ sym = menu->sym;
+
+ if (!sym || sym_is_choice(sym))
+ continue;
+
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ continue;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* Skip unchangeable symbols */
+ if (!sym_is_changeable(sym))
+ continue;
+ /* Skip symbols that are equal to the default */
+ if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
+ continue;
+
+ /* Skip choice values that are equal to the default */
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
+ struct symbol *ds;
+
+ ds = sym_choice_default(choice);
+ if (sym == ds && sym_get_tristate_value(sym) == yes)
+ continue;
+ }
+ print_symbol_for_dotconfig(out, sym);
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *str;
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
+ char *env;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
+
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (env && *env) {
+ *tmpname = 0;
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &comment_style_pound);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ need_newline = false;
+ } else if (!sym_is_choice(sym) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
+ print_symbol_for_dotconfig(out, sym);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+
+end_check:
+ if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
+ menu->prompt->type == P_MENU) {
+ fprintf(out, "# end of %s\n", menu_get_prompt(menu));
+ need_newline = true;
+ }
+
+ if (menu->next) {
+ menu = menu->next;
+ } else {
+ menu = menu->parent;
+ if (menu)
+ goto end_check;
+ }
+ }
+ fclose(out);
+
+ for_all_symbols(sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
+ if (*tmpname) {
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ conf_set_changed(false);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
+ return 1;
+ }
+
+ conf_message("configuration written to %s", name);
+
+ conf_set_changed(false);
+
+ return 0;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_autoconf_cmd(const char *autoconf_name)
+{
+ char name[PATH_MAX], tmp[PATH_MAX];
+ FILE *out;
+ int ret;
+
+ ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+ if (ret >= sizeof(name)) /* check truncation */
+ return -1;
+
+ if (make_parent_dir(name))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ out = fopen(tmp, "w");
+ if (!out) {
+ perror("fopen");
+ return -1;
+ }
+
+ fprintf(out, "autoconfig := %s\n", autoconf_name);
+
+ fputs(str_get(&autoconf_cmd), out);
+
+ fflush(out);
+ ret = ferror(out); /* error check for all fprintf() calls */
+ fclose(out);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, name)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int conf_touch_deps(void)
+{
+ const char *name, *tmp;
+ struct symbol *sym;
+ int res;
+
+ name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+
+ for_all_symbols(sym) {
+ if (sym_is_choice(sym))
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int __conf_write_autoconf(const char *filename,
+ void (*print_symbol)(FILE *, struct symbol *),
+ const struct comment_style *comment_style)
+{
+ char tmp[PATH_MAX];
+ FILE *file;
+ struct symbol *sym;
+ int ret;
+
+ if (make_parent_dir(filename))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ file = fopen(tmp, "w");
+ if (!file) {
+ perror("fopen");
+ return -1;
+ }
+
+ conf_write_heading(file, comment_style);
+
+ for_all_symbols(sym)
+ if ((sym->flags & SYMBOL_WRITE) && sym->name)
+ print_symbol(file, sym);
+
+ fflush(file);
+ /* check possible errors in conf_write_heading() and print_symbol() */
+ ret = ferror(file);
+ fclose(file);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, filename)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+int conf_write_autoconf(int overwrite)
+{
+ struct symbol *sym;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ int ret;
+
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
+ ret = conf_write_autoconf_cmd(autoconf_name);
+ if (ret)
+ return -1;
+
+ for_all_symbols(sym)
+ sym_calc_value(sym);
+
+ if (conf_touch_deps())
+ return 1;
+
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+ if (ret)
+ return ret;
+
+ ret = __conf_write_autoconf(conf_get_rustccfg_name(),
+ print_symbol_for_rustccfg,
+ NULL);
+ if (ret)
+ return ret;
+
+ /*
+ * Create include/config/auto.conf. This must be the last step because
+ * Kbuild has a dependency on auto.conf and this marks the successful
+ * completion of the previous steps.
+ */
+ ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+ print_symbol_for_autoconf,
+ &comment_style_pound);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static bool conf_changed;
+static void (*conf_changed_callback)(bool);
+
+void conf_set_changed(bool val)
+{
+ if (conf_changed_callback && conf_changed != val)
+ conf_changed_callback(val);
+
+ conf_changed = val;
+}
+
+bool conf_get_changed(void)
+{
+ return conf_changed;
+}
+
+void conf_set_changed_callback(void (*fn)(bool))
+{
+ conf_changed_callback = fn;
+}
diff --git a/scripts/kconfig/dialog.h b/scripts/kconfig/dialog.h
new file mode 100644
index 00000000..f6c2ebe6
--- /dev/null
+++ b/scripts/kconfig/dialog.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include <ncurses.h>
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ * Color definitions
+ */
+struct dialog_color {
+ chtype atr; /* Color attribute */
+ int fg; /* foreground */
+ int bg; /* background */
+ int hl; /* highlight this item */
+};
+
+struct subtitle_list {
+ struct subtitle_list *next;
+ const char *text;
+};
+
+struct dialog_info {
+ const char *backtitle;
+ struct subtitle_list *subtitles;
+ struct dialog_color screen;
+ struct dialog_color shadow;
+ struct dialog_color dialog;
+ struct dialog_color title;
+ struct dialog_color border;
+ struct dialog_color button_active;
+ struct dialog_color button_inactive;
+ struct dialog_color button_key_active;
+ struct dialog_color button_key_inactive;
+ struct dialog_color button_label_active;
+ struct dialog_color button_label_inactive;
+ struct dialog_color inputbox;
+ struct dialog_color position_indicator;
+ struct dialog_color menubox;
+ struct dialog_color menubox_border;
+ struct dialog_color item;
+ struct dialog_color item_selected;
+ struct dialog_color tag;
+ struct dialog_color tag_selected;
+ struct dialog_color tag_key;
+ struct dialog_color tag_key_selected;
+ struct dialog_color check;
+ struct dialog_color check_selected;
+ struct dialog_color uarrow;
+ struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+ char str[MAXITEMSTR]; /* prompt displayed */
+ char tag;
+ void *data; /* pointer to menu item - used by menubox+checklist */
+ int selected; /* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+ struct dialog_item node;
+ struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+ for (item_cur = item_head ? item_head: item_cur; \
+ item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+/* minimum (re)size values */
+#define CHECKLIST_HEIGHT_MIN 6 /* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGHT_MIN 2 /* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGHT_MIN 15 /* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGHT_MIN 8 /* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGHT_MIN 4 /* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGHT_MIN 19 /* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void set_dialog_subtitles(struct subtitle_list *subtitles);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+ chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+ int width, int pause);
+int dialog_textbox(const char *title, const char *tbuf, int initial_height,
+ int initial_width, int *_vscroll, int *_hscroll,
+ int (*extra_key_cb)(int, size_t, size_t, void *), void *data);
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height);
+int dialog_inputbox(const char *title, const char *prompt, int height,
+ int width, const char *init);
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
new file mode 100644
index 00000000..16f92c4a
--- /dev/null
+++ b/scripts/kconfig/expr.c
@@ -0,0 +1,1180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hash.h>
+#include <xalloc.h>
+#include "internal.h"
+#include "lkc.h"
+
+#define DEBUG_EXPR 0
+
+HASHTABLE_DEFINE(expr_hashtable, EXPR_HASHSIZE);
+
+static struct expr *expr_eliminate_yn(struct expr *e);
+
+/**
+ * expr_lookup - return the expression with the given type and sub-nodes
+ * This looks up an expression with the specified type and sub-nodes. If such
+ * an expression is found in the hash table, it is returned. Otherwise, a new
+ * expression node is allocated and added to the hash table.
+ * @type: expression type
+ * @l: left node
+ * @r: right node
+ * return: expression
+ */
+static struct expr *expr_lookup(enum expr_type type, void *l, void *r)
+{
+ struct expr *e;
+ int hash;
+
+ hash = hash_32((unsigned int)type ^ hash_ptr(l) ^ hash_ptr(r));
+
+ hash_for_each_possible(expr_hashtable, e, node, hash) {
+ if (e->type == type && e->left._initdata == l &&
+ e->right._initdata == r)
+ return e;
+ }
+
+ e = xmalloc(sizeof(*e));
+ e->type = type;
+ e->left._initdata = l;
+ e->right._initdata = r;
+ e->val_is_valid = false;
+
+ hash_add(expr_hashtable, &e->node, hash);
+
+ return e;
+}
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ return expr_lookup(E_SYMBOL, sym, NULL);
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+ return expr_lookup(type, ce, NULL);
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+ return expr_lookup(type, e1, e2);
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+ return expr_lookup(type, s1, s2);
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+static int trans_count;
+
+/*
+ * 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)
+{
+ struct expr *l, *r;
+
+ /* Recurse down to leaves */
+
+ if ((*ep1)->type == type) {
+ l = (*ep1)->left.expr;
+ r = (*ep1)->right.expr;
+ __expr_eliminate_eq(type, &l, ep2);
+ __expr_eliminate_eq(type, &r, ep2);
+ *ep1 = expr_alloc_two(type, l, r);
+ return;
+ }
+ if ((*ep2)->type == type) {
+ l = (*ep2)->left.expr;
+ r = (*ep2)->right.expr;
+ __expr_eliminate_eq(type, ep1, &l);
+ __expr_eliminate_eq(type, ep1, &r);
+ *ep2 = expr_alloc_two(type, l, r);
+ return;
+ }
+
+ /* *ep1 and *ep2 are leaves. Compare them. */
+
+ if ((*ep1)->type == E_SYMBOL && (*ep2)->type == E_SYMBOL &&
+ (*ep1)->left.sym == (*ep2)->left.sym &&
+ ((*ep1)->left.sym == &symbol_yes || (*ep1)->left.sym == &symbol_no))
+ return;
+ if (!expr_eq(*ep1, *ep2))
+ return;
+
+ /* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */
+
+ trans_count++;
+ switch (type) {
+ case E_OR:
+ *ep1 = expr_alloc_symbol(&symbol_no);
+ *ep2 = expr_alloc_symbol(&symbol_no);
+ break;
+ case E_AND:
+ *ep1 = expr_alloc_symbol(&symbol_yes);
+ *ep2 = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+}
+
+/*
+ * 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 (!*ep1 || !*ep2)
+ return;
+ switch ((*ep1)->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq((*ep1)->type, ep1, ep2);
+ default:
+ ;
+ }
+ if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq((*ep2)->type, ep1, ep2);
+ default:
+ ;
+ }
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+}
+
+/*
+ * 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.
+ */
+bool expr_eq(struct expr *e1, struct expr *e2)
+{
+ int old_count;
+ bool res;
+
+ /*
+ * A NULL expr is taken to be yes, but there's also a different way to
+ * represent yes. expr_is_yes() checks for either representation.
+ */
+ if (!e1 || !e2)
+ return expr_is_yes(e1) && expr_is_yes(e2);
+
+ if (e1->type != e2->type)
+ return false;
+ switch (e1->type) {
+ case E_EQUAL:
+ case E_GEQ:
+ case E_GTH:
+ case E_LEQ:
+ case E_LTH:
+ case E_UNEQUAL:
+ return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+ case E_SYMBOL:
+ return e1->left.sym == e2->left.sym;
+ case E_NOT:
+ return expr_eq(e1->left.expr, e2->left.expr);
+ case E_AND:
+ case E_OR:
+ old_count = trans_count;
+ expr_eliminate_eq(&e1, &e2);
+ res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym);
+ trans_count = old_count;
+ return res;
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+
+ if (DEBUG_EXPR) {
+ expr_fprint(e1, stdout);
+ printf(" = ");
+ expr_fprint(e2, stdout);
+ printf(" ?\n");
+ }
+
+ return false;
+}
+
+/*
+ * Recursively performs the following simplifications (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 *l, *r;
+
+ if (e) switch (e->type) {
+ case E_AND:
+ l = expr_eliminate_yn(e->left.expr);
+ r = expr_eliminate_yn(e->right.expr);
+ if (l->type == E_SYMBOL) {
+ if (l->left.sym == &symbol_no)
+ return l;
+ else if (l->left.sym == &symbol_yes)
+ return r;
+ }
+ if (r->type == E_SYMBOL) {
+ if (r->left.sym == &symbol_no)
+ return r;
+ else if (r->left.sym == &symbol_yes)
+ return l;
+ }
+ break;
+ case E_OR:
+ l = expr_eliminate_yn(e->left.expr);
+ r = expr_eliminate_yn(e->right.expr);
+ if (l->type == E_SYMBOL) {
+ if (l->left.sym == &symbol_no)
+ return r;
+ else if (l->left.sym == &symbol_yes)
+ return l;
+ }
+ if (r->type == E_SYMBOL) {
+ if (r->left.sym == &symbol_no)
+ return l;
+ else if (r->left.sym == &symbol_yes)
+ return r;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return e1;
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='m') -> (a!='n')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='n') -> (a!='m')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+ // (a='m') || (a='n') -> (a!='y')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+ }
+ }
+ if (sym1->type == S_BOOLEAN) {
+ // a || !a -> y
+ if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+ (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+ return expr_alloc_symbol(&symbol_yes);
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") || (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return e1;
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+ // (a) && (a='y') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+ // (a) && (a!='n') -> (a)
+ return expr_alloc_symbol(sym1);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+ // (a) && (a!='m') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e1->right.sym;
+ if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e2->right.sym;
+ if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='m') -> (a='n')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+ // (a!='m') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+ (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+ return NULL;
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") && (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ 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)
+{
+ struct expr *tmp, *l, *r;
+
+ /* Recurse down to leaves */
+
+ if ((*ep1)->type == type) {
+ l = (*ep1)->left.expr;
+ r = (*ep1)->right.expr;
+ expr_eliminate_dups1(type, &l, ep2);
+ expr_eliminate_dups1(type, &r, ep2);
+ *ep1 = expr_alloc_two(type, l, r);
+ return;
+ }
+ if ((*ep2)->type == type) {
+ l = (*ep2)->left.expr;
+ r = (*ep2)->right.expr;
+ expr_eliminate_dups1(type, ep1, &l);
+ expr_eliminate_dups1(type, ep1, &r);
+ *ep2 = expr_alloc_two(type, l, r);
+ return;
+ }
+
+ /* *ep1 and *ep2 are leaves. Compare and process them. */
+
+ switch (type) {
+ case E_OR:
+ tmp = expr_join_or(*ep1, *ep2);
+ if (tmp) {
+ *ep1 = expr_alloc_symbol(&symbol_no);
+ *ep2 = tmp;
+ trans_count++;
+ }
+ break;
+ case E_AND:
+ tmp = expr_join_and(*ep1, *ep2);
+ if (tmp) {
+ *ep1 = expr_alloc_symbol(&symbol_yes);
+ *ep2 = tmp;
+ trans_count++;
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+/*
+ * 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;
+ if (!e)
+ return e;
+
+ oldcount = trans_count;
+ do {
+ struct expr *l, *r;
+
+ trans_count = 0;
+ switch (e->type) {
+ case E_OR: case E_AND:
+ l = expr_eliminate_dups(e->left.expr);
+ r = expr_eliminate_dups(e->right.expr);
+ expr_eliminate_dups1(e->type, &l, &r);
+ e = expr_alloc_two(e->type, l, r);
+ default:
+ ;
+ }
+ e = expr_eliminate_yn(e);
+ } while (trans_count); /* repeat until we get no more simplifications */
+ trans_count = oldcount;
+ return e;
+}
+
+/*
+ * Performs various simplifications involving logical operators and
+ * comparisons.
+ *
+ * For bool type:
+ * A=n -> !A
+ * A=m -> n
+ * A=y -> A
+ * A!=n -> A
+ * A!=m -> y
+ * A!=y -> !A
+ *
+ * For any type:
+ * !!A -> A
+ * !(A=B) -> A!=B
+ * !(A!=B) -> A=B
+ * !(A<=B) -> A>B
+ * !(A>=B) -> A<B
+ * !(A<B) -> A>=B
+ * !(A>B) -> A<=B
+ * !(A || B) -> !A && !B
+ * !(A && B) -> !A || !B
+ *
+ * For constant:
+ * !y -> n
+ * !m -> m
+ * !n -> y
+ *
+ * Allocates and returns a new expression.
+ */
+struct expr *expr_transform(struct expr *e)
+{
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_EQUAL:
+ case E_GEQ:
+ case E_GTH:
+ case E_LEQ:
+ case E_LTH:
+ case E_UNEQUAL:
+ case E_SYMBOL:
+ break;
+ default:
+ e = expr_alloc_two(e->type,
+ expr_transform(e->left.expr),
+ expr_transform(e->right.expr));
+ }
+
+ switch (e->type) {
+ case E_EQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ // A=n -> !A
+ e = expr_alloc_one(E_NOT, expr_alloc_symbol(e->left.sym));
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ // A=m -> n
+ printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+ e = expr_alloc_symbol(&symbol_no);
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ // A=y -> A
+ e = expr_alloc_symbol(e->left.sym);
+ break;
+ }
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ // A!=n -> A
+ e = expr_alloc_symbol(e->left.sym);
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ // A!=m -> y
+ printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+ e = expr_alloc_symbol(&symbol_yes);
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ // A!=y -> !A
+ e = expr_alloc_one(E_NOT, e->left.expr);
+ break;
+ }
+ break;
+ case E_NOT:
+ switch (e->left.expr->type) {
+ case E_NOT:
+ // !!A -> A
+ e = e->left.expr->left.expr;
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ // !(A=B) -> A!=B
+ e = expr_alloc_comp(e->left.expr->type == E_EQUAL ? E_UNEQUAL : E_EQUAL,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
+ break;
+ case E_LEQ:
+ case E_GEQ:
+ // !(A<=B) -> A>B
+ e = expr_alloc_comp(e->left.expr->type == E_LEQ ? E_GTH : E_LTH,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
+ break;
+ case E_LTH:
+ case E_GTH:
+ // !(A<B) -> A>=B
+ e = expr_alloc_comp(e->left.expr->type == E_LTH ? E_GEQ : E_LEQ,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
+ break;
+ case E_OR:
+ // !(A || B) -> !A && !B
+ e = expr_alloc_and(expr_alloc_one(E_NOT, e->left.expr->left.expr),
+ expr_alloc_one(E_NOT, e->left.expr->right.expr));
+ e = expr_transform(e);
+ break;
+ case E_AND:
+ // !(A && B) -> !A || !B
+ e = expr_alloc_or(expr_alloc_one(E_NOT, e->left.expr->left.expr),
+ expr_alloc_one(E_NOT, e->left.expr->right.expr));
+ e = expr_transform(e);
+ break;
+ case E_SYMBOL:
+ if (e->left.expr->left.sym == &symbol_yes)
+ // !'y' -> 'n'
+ e = expr_alloc_symbol(&symbol_no);
+ else if (e->left.expr->left.sym == &symbol_mod)
+ // !'m' -> 'm'
+ e = expr_alloc_symbol(&symbol_mod);
+ else if (e->left.expr->left.sym == &symbol_no)
+ // !'n' -> 'y'
+ e = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+bool expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return false;
+
+ switch (dep->type) {
+ case E_AND:
+ case E_OR:
+ return expr_contains_symbol(dep->left.expr, sym) ||
+ expr_contains_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ case E_GEQ:
+ case E_GTH:
+ case E_LEQ:
+ case E_LTH:
+ case E_UNEQUAL:
+ return dep->left.sym == sym ||
+ dep->right.sym == sym;
+ case E_NOT:
+ return expr_contains_symbol(dep->left.expr, sym);
+ default:
+ ;
+ }
+ return false;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return false;
+
+ switch (dep->type) {
+ case E_AND:
+ return expr_depends_symbol(dep->left.expr, sym) ||
+ expr_depends_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+ return true;
+ }
+ break;
+ case E_UNEQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_no)
+ return true;
+ }
+ break;
+ default:
+ ;
+ }
+ 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;
+
+ if (!e) {
+ e = expr_alloc_symbol(sym);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ }
+ switch (e->type) {
+ case E_AND:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_OR:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_NOT:
+ return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+ case E_UNEQUAL:
+ case E_LTH:
+ case E_LEQ:
+ case E_GTH:
+ case E_GEQ:
+ case E_EQUAL:
+ if (type == E_EQUAL) {
+ if (sym == &symbol_yes)
+ return e;
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_no);
+ if (sym == &symbol_no)
+ return expr_alloc_one(E_NOT, e);
+ } else {
+ if (sym == &symbol_yes)
+ return expr_alloc_one(E_NOT, e);
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_yes);
+ if (sym == &symbol_no)
+ return e;
+ }
+ break;
+ case E_SYMBOL:
+ return expr_alloc_comp(type, e->left.sym, sym);
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+ return NULL;
+}
+
+enum string_value_kind {
+ k_string,
+ k_signed,
+ k_unsigned,
+};
+
+union string_value {
+ unsigned long long u;
+ signed long long s;
+};
+
+static enum string_value_kind expr_parse_string(const char *str,
+ enum symbol_type type,
+ union string_value *val)
+{
+ char *tail;
+ enum string_value_kind kind;
+
+ errno = 0;
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ val->s = !strcmp(str, "n") ? 0 :
+ !strcmp(str, "m") ? 1 :
+ !strcmp(str, "y") ? 2 : -1;
+ return k_signed;
+ case S_INT:
+ val->s = strtoll(str, &tail, 10);
+ kind = k_signed;
+ break;
+ case S_HEX:
+ val->u = strtoull(str, &tail, 16);
+ kind = k_unsigned;
+ break;
+ default:
+ val->s = strtoll(str, &tail, 0);
+ kind = k_signed;
+ break;
+ }
+ return !errno && !*tail && tail > str && isxdigit(tail[-1])
+ ? kind : k_string;
+}
+
+static tristate __expr_calc_value(struct expr *e)
+{
+ tristate val1, val2;
+ const char *str1, *str2;
+ enum string_value_kind k1 = k_string, k2 = k_string;
+ union string_value lval = {}, rval = {};
+ int res;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ sym_calc_value(e->left.sym);
+ return e->left.sym->curr.tri;
+ case E_AND:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_AND(val1, val2);
+ case E_OR:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_OR(val1, val2);
+ case E_NOT:
+ val1 = expr_calc_value(e->left.expr);
+ return EXPR_NOT(val1);
+ case E_EQUAL:
+ case E_GEQ:
+ case E_GTH:
+ case E_LEQ:
+ case E_LTH:
+ case E_UNEQUAL:
+ break;
+ default:
+ printf("expr_calc_value: %d?\n", e->type);
+ return no;
+ }
+
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+
+ if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
+ k1 = expr_parse_string(str1, e->left.sym->type, &lval);
+ k2 = expr_parse_string(str2, e->right.sym->type, &rval);
+ }
+
+ if (k1 == k_string || k2 == k_string)
+ res = strcmp(str1, str2);
+ 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);
+
+ switch(e->type) {
+ case E_EQUAL:
+ return res ? no : yes;
+ case E_GEQ:
+ return res >= 0 ? yes : no;
+ case E_GTH:
+ return res > 0 ? yes : no;
+ case E_LEQ:
+ return res <= 0 ? yes : no;
+ case E_LTH:
+ return res < 0 ? yes : no;
+ case E_UNEQUAL:
+ return res ? yes : no;
+ default:
+ printf("expr_calc_value: relation %d?\n", e->type);
+ return no;
+ }
+}
+
+/**
+ * expr_calc_value - return the tristate value of the given expression
+ * @e: expression
+ * return: tristate value of the expression
+ */
+tristate expr_calc_value(struct expr *e)
+{
+ if (!e)
+ return yes;
+
+ if (!e->val_is_valid) {
+ e->val = __expr_calc_value(e);
+ e->val_is_valid = true;
+ }
+
+ return e->val;
+}
+
+/**
+ * expr_invalidate_all - invalidate all cached expression values
+ */
+void expr_invalidate_all(void)
+{
+ struct expr *e;
+
+ hash_for_each(expr_hashtable, e, node)
+ e->val_is_valid = false;
+}
+
+static int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+ if (t1 == t2)
+ return 0;
+ switch (t1) {
+ case E_LEQ:
+ case E_LTH:
+ case E_GEQ:
+ case E_GTH:
+ if (t2 == E_EQUAL || t2 == E_UNEQUAL)
+ return 1;
+ /* fallthrough */
+ case E_EQUAL:
+ case E_UNEQUAL:
+ if (t2 == E_NOT)
+ return 1;
+ /* fallthrough */
+ case E_NOT:
+ if (t2 == E_AND)
+ return 1;
+ /* fallthrough */
+ case E_AND:
+ if (t2 == E_OR)
+ return 1;
+ /* fallthrough */
+ default:
+ break;
+ }
+ return 0;
+}
+
+void expr_print(const struct expr *e,
+ void (*fn)(void *, struct symbol *, const char *),
+ void *data, int prevtoken)
+{
+ if (!e) {
+ fn(data, NULL, "y");
+ return;
+ }
+
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, "(");
+ switch (e->type) {
+ case E_SYMBOL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ break;
+ case E_NOT:
+ fn(data, NULL, "!");
+ expr_print(e->left.expr, fn, data, E_NOT);
+ break;
+ case E_EQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_LEQ:
+ case E_LTH:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_GEQ:
+ case E_GTH:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "!=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_OR:
+ expr_print(e->left.expr, fn, data, E_OR);
+ fn(data, NULL, " || ");
+ expr_print(e->right.expr, fn, data, E_OR);
+ break;
+ case E_AND:
+ expr_print(e->left.expr, fn, data, E_AND);
+ fn(data, NULL, " && ");
+ expr_print(e->right.expr, fn, data, E_AND);
+ break;
+ case E_RANGE:
+ fn(data, NULL, "[");
+ fn(data, e->left.sym, e->left.sym->name);
+ fn(data, NULL, " ");
+ fn(data, e->right.sym, e->right.sym->name);
+ fn(data, NULL, "]");
+ break;
+ default:
+ {
+ char buf[32];
+ sprintf(buf, "<unknown type %d>", e->type);
+ fn(data, NULL, buf);
+ break;
+ }
+ }
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+ xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+ expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+ struct gstr *gs = (struct gstr*)data;
+ const char *sym_str = NULL;
+
+ if (sym)
+ sym_str = sym_get_string_value(sym);
+
+ if (gs->max_width) {
+ unsigned extra_length = strlen(str);
+ const char *last_cr = strrchr(gs->s, '\n');
+ unsigned last_line_length;
+
+ if (sym_str)
+ extra_length += 4 + strlen(sym_str);
+
+ if (!last_cr)
+ last_cr = gs->s;
+
+ last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+ if ((last_line_length + extra_length) > gs->max_width)
+ str_append(gs, "\\\n");
+ }
+
+ str_append(gs, str);
+ if (sym && sym->type != S_UNKNOWN)
+ str_printf(gs, " [=%s]", sym_str);
+}
+
+void expr_gstr_print(const 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/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
new file mode 100644
index 00000000..5f900d18
--- /dev/null
+++ b/scripts/kconfig/expr.h
@@ -0,0 +1,328 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include <list_types.h>
+
+typedef enum tristate {
+ no, mod, yes
+} tristate;
+
+enum expr_type {
+ E_NONE, E_OR, E_AND, E_NOT,
+ E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
+ E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+ struct expr * const expr;
+ struct symbol * const sym;
+ void *_initdata;
+};
+
+/**
+ * struct expr - expression
+ *
+ * @node: link node for the hash table
+ * @type: expressoin type
+ * @val: calculated tristate value
+ * @val_is_valid: indicate whether the value is valid
+ * @left: left node
+ * @right: right node
+ */
+struct expr {
+ struct hlist_node node;
+ enum expr_type type;
+ tristate val;
+ bool val_is_valid;
+ union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep) (2-(dep))
+
+struct expr_value {
+ struct expr *expr;
+ tristate tri;
+};
+
+struct symbol_value {
+ void *val;
+ tristate tri;
+};
+
+enum symbol_type {
+ S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+ S_DEF_USER, /* main user value */
+ S_DEF_AUTO, /* values read from auto.conf */
+ S_DEF_DEF3, /* Reserved for UI usage */
+ S_DEF_DEF4, /* Reserved for UI usage */
+ S_DEF_COUNT
+};
+
+/*
+ * Represents a configuration symbol.
+ *
+ * Choices are represented as a special kind of symbol with null name.
+ *
+ * @choice_link: linked to menu::choice_members
+ */
+struct symbol {
+ /* link node for the hash table */
+ struct hlist_node node;
+
+ /* 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;
+
+ /* config entries associated with this symbol */
+ struct list_head menus;
+
+ struct list_head choice_link;
+
+ /* 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 SYMBOL_CONST 0x0001 /* symbol is const */
+#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
+#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
+#define SYMBOL_TRANS 0x0100 /* symbol is transitional only (not visible)*/
+#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
+#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
+#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
+#define SYMBOL_WARNED 0x8000 /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
+
+#define SYMBOL_MAXLENGTH 256
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ * default y
+ * prompt "foo prompt"
+ * select BAR
+ * config BAZ
+ * int "BAZ Value"
+ * range 1..255
+ *
+ * Please, also check parser.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 menu or menuconfig symbol */
+ P_DEFAULT, /* default y */
+ P_SELECT, /* select BAR */
+ P_IMPLY, /* imply BAR */
+ P_RANGE, /* range 7..100 (for a symbol) */
+};
+
+struct property {
+ struct property *next; /* next property - null if last */
+ enum prop_type type; /* type of property */
+ const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+ struct expr_value visible;
+ struct expr *expr; /* the optional conditional part of the property */
+ struct menu *menu; /* the menu the property are associated with
+ * valid for: P_SELECT, P_RANGE,
+ * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+ const char *filename; /* what file was this property defined */
+ int lineno; /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_prompts(sym, st) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->text)
+
+enum menu_type {
+ M_CHOICE, // "choice"
+ M_COMMENT, // "comment"
+ M_IF, // "if"
+ M_MENU, // "mainmenu", "menu", "menuconfig"
+ M_NORMAL, // others, i.e., "config"
+};
+
+/*
+ * 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.
+ *
+ * @type: type of the menu entry
+ * @choice_members: list of choice members with priority.
+ */
+struct menu {
+ enum menu_type type;
+
+ /* 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;
+
+ struct list_head link; /* link to symbol::menus */
+
+ struct list_head choice_members;
+
+ /*
+ * 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 */
+ const char *filename;
+ 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 {
+ struct list_head entries;
+ size_t offset;
+ struct menu *target;
+};
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+bool expr_eq(struct expr *e1, struct expr *e2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+bool 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);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(const 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 bool expr_is_yes(const struct expr *e)
+{
+ return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/scripts/kconfig/images.c b/scripts/kconfig/images.c
new file mode 100644
index 00000000..2f9afffa
--- /dev/null
+++ b/scripts/kconfig/images.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include "images.h"
+
+const char * const xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+const char * const xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+const char * const xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+const char * const xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+const char * const xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+const char * const xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+const char * const xpm_symbol_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+const char * const xpm_symbol_mod[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+const char * const xpm_symbol_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . . ",
+" . .. . ",
+" . . .. . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+const char * const xpm_choice_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+const char * const xpm_choice_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+const char * const xpm_menu[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+const char * const xpm_menu_inv[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" .......... ",
+" .. ...... ",
+" .. .... ",
+" .. .. ",
+" .. .. ",
+" .. .... ",
+" .. ...... ",
+" .......... ",
+" .......... ",
+" "};
+
+const char * const xpm_menuback[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+const char * const xpm_void[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/scripts/kconfig/images.h b/scripts/kconfig/images.h
new file mode 100644
index 00000000..7212dec2
--- /dev/null
+++ b/scripts/kconfig/images.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#ifndef IMAGES_H
+#define IMAGES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char * const xpm_load[];
+extern const char * const xpm_save[];
+extern const char * const xpm_back[];
+extern const char * const xpm_tree_view[];
+extern const char * const xpm_single_view[];
+extern const char * const xpm_split_view[];
+extern const char * const xpm_symbol_no[];
+extern const char * const xpm_symbol_mod[];
+extern const char * const xpm_symbol_yes[];
+extern const char * const xpm_choice_no[];
+extern const char * const xpm_choice_yes[];
+extern const char * const xpm_menu[];
+extern const char * const xpm_menu_inv[];
+extern const char * const xpm_menuback[];
+extern const char * const xpm_void[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IMAGES_H */
diff --git a/scripts/kconfig/include/array_size.h b/scripts/kconfig/include/array_size.h
new file mode 100644
index 00000000..26ba78d8
--- /dev/null
+++ b/scripts/kconfig/include/array_size.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARRAY_SIZE_H
+#define ARRAY_SIZE_H
+
+/**
+ * ARRAY_SIZE - get the number of elements in array @arr
+ * @arr: array to be sized
+ */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#endif /* ARRAY_SIZE_H */
diff --git a/scripts/kconfig/include/config/auto.conf b/scripts/kconfig/include/config/auto.conf
new file mode 100644
index 00000000..a518ebb0
--- /dev/null
+++ b/scripts/kconfig/include/config/auto.conf
@@ -0,0 +1,4 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# System Configuration
+#
diff --git a/scripts/kconfig/include/config/auto.conf.cmd b/scripts/kconfig/include/config/auto.conf.cmd
new file mode 100644
index 00000000..7c8c63bd
--- /dev/null
+++ b/scripts/kconfig/include/config/auto.conf.cmd
@@ -0,0 +1,7 @@
+autoconfig := include/config/auto.conf
+
+deps_config := \
+ /Users/fenze/Developer/openlinux/ref/Kconfig \
+
+$(autoconfig): $(deps_config)
+$(deps_config): ;
diff --git a/scripts/kconfig/include/generated/autoconf.h b/scripts/kconfig/include/generated/autoconf.h
new file mode 100644
index 00000000..96182c24
--- /dev/null
+++ b/scripts/kconfig/include/generated/autoconf.h
@@ -0,0 +1,4 @@
+/*
+ * Automatically generated file; DO NOT EDIT.
+ * System Configuration
+ */
diff --git a/scripts/kconfig/include/generated/rustc_cfg b/scripts/kconfig/include/generated/rustc_cfg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/scripts/kconfig/include/generated/rustc_cfg
diff --git a/scripts/kconfig/include/hash.h b/scripts/kconfig/include/hash.h
new file mode 100644
index 00000000..efa90436
--- /dev/null
+++ b/scripts/kconfig/include/hash.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef HASH_H
+#define HASH_H
+
+static inline unsigned int hash_str(const char *s)
+{
+ /* fnv32 hash */
+ unsigned int hash = 2166136261U;
+
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
+/* simplified version of functions from include/linux/hash.h */
+#define GOLDEN_RATIO_32 0x61C88647
+
+static inline unsigned int hash_32(unsigned int val)
+{
+ return 0x61C88647 * val;
+}
+
+static inline unsigned int hash_ptr(const void *ptr)
+{
+ return hash_32((unsigned int)(unsigned long)ptr);
+}
+
+#endif /* HASH_H */
diff --git a/scripts/kconfig/include/hashtable.h b/scripts/kconfig/include/hashtable.h
new file mode 100644
index 00000000..45abcb12
--- /dev/null
+++ b/scripts/kconfig/include/hashtable.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef HASHTABLE_H
+#define HASHTABLE_H
+
+#include "array_size.h"
+#include "list.h"
+
+#define HASH_SIZE(name) (ARRAY_SIZE(name))
+
+#define HASHTABLE_DECLARE(name, size) struct hlist_head name[size]
+
+#define HASHTABLE_DEFINE(name, size) \
+ HASHTABLE_DECLARE(name, size) = \
+ { [0 ... ((size) - 1)] = HLIST_HEAD_INIT }
+
+#define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)])
+
+static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
+{
+ unsigned int i;
+
+ for (i = 0; i < sz; i++)
+ INIT_HLIST_HEAD(&ht[i]);
+}
+
+/**
+ * hash_init - initialize a hash table
+ * @table: hashtable to be initialized
+ *
+ * This has to be a macro since HASH_SIZE() will not work on pointers since
+ * it calculates the size during preprocessing.
+ */
+#define hash_init(table) __hash_init(table, HASH_SIZE(table))
+
+/**
+ * hash_add - add an object to a hashtable
+ * @table: hashtable to add to
+ * @node: the &struct hlist_node of the object to be added
+ * @key: the key of the object to be added
+ */
+#define hash_add(table, node, key) \
+ hlist_add_head(node, hash_head(table, key))
+
+/**
+ * hash_del - remove an object from a hashtable
+ * @node: &struct hlist_node of the object to remove
+ */
+static inline void hash_del(struct hlist_node *node)
+{
+ hlist_del_init(node);
+}
+
+/**
+ * hash_for_each - iterate over a hashtable
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each(table, obj, member) \
+ for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \
+ hlist_for_each_entry(obj, &table[_bkt], member)
+
+/**
+ * hash_for_each_safe - iterate over a hashtable safe against removal of
+ * hash entry
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @tmp: a &struct hlist_node used for temporary storage
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each_safe(table, obj, tmp, member) \
+ for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \
+ hlist_for_each_entry_safe(obj, tmp, &table[_bkt], member)
+
+/**
+ * hash_for_each_possible - iterate over all possible objects hashing to the
+ * same bucket
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible(table, obj, member, key) \
+ hlist_for_each_entry(obj, hash_head(table, key), member)
+
+/**
+ * hash_for_each_possible_safe - iterate over all possible objects hashing to the
+ * same bucket safe against removals
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @tmp: a &struct hlist_node used for temporary storage
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible_safe(table, obj, tmp, member, key) \
+ hlist_for_each_entry_safe(obj, tmp, hash_head(table, key), member)
+
+#endif /* HASHTABLE_H */
diff --git a/scripts/kconfig/include/list.h b/scripts/kconfig/include/list.h
new file mode 100644
index 00000000..8bdcaadc
--- /dev/null
+++ b/scripts/kconfig/include/list.h
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LIST_H
+#define LIST_H
+
+#include <stddef.h>
+
+#include "list_types.h"
+
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ void *__mptr = (void *)(ptr); \
+ _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
+ __same_type(*(ptr), void), \
+ "pointer type mismatch in container_of()"); \
+ ((type *)(__mptr - offsetof(type, member))); })
+
+#define LIST_POISON1 ((void *) 0x100)
+#define LIST_POISON2 ((void *) 0x122)
+
+/*
+ * Circular doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * INIT_LIST_HEAD - Initialize a list_head structure
+ * @list: list_head structure to be initialized.
+ *
+ * Initializes the list_head to point to itself. If it is a list header,
+ * the result is an empty list.
+ */
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del_entry(entry);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+/**
+ * list_replace_init - replace old entry by new one and initialize the old one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_first -- tests whether @list is the first entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_first(const struct list_head *list, const struct list_head *head)
+{
+ return list->prev == head;
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list, const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_is_head - tests whether @list is the list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+{
+ return list == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_prev_entry - get the prev element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_prev_entry(pos, member) \
+ list_entry((pos)->member.prev, typeof(*(pos)), member)
+
+/**
+ * list_entry_is_head - test if the entry points to the head of the list
+ * @pos: the type * to cursor
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry_is_head(pos, head, member) \
+ (&pos->member == (head))
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member); \
+ !list_entry_is_head(pos, head, member); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_last_entry(head, typeof(*pos), member); \
+ !list_entry_is_head(pos, head, member); \
+ pos = list_prev_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member), \
+ n = list_next_entry(pos, member); \
+ !list_entry_is_head(pos, head, member); \
+ pos = n, n = list_next_entry(n, member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+/**
+ * hlist_unhashed - Has node been removed from list and reinitialized?
+ * @h: Node to be checked
+ *
+ * Not that not all removal functions will leave a node in unhashed
+ * state. For example, hlist_nulls_del_init_rcu() does leave the
+ * node in unhashed state, but hlist_nulls_del() does not.
+ */
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+/**
+ * hlist_del - Delete the specified hlist_node from its list
+ * @n: Node to delete.
+ *
+ * Note that this function leaves the node in hashed state. Use
+ * hlist_del_init() or similar instead to unhash @n.
+ */
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_init - Delete the specified hlist_node from its list and initialize
+ * @n: Node to delete.
+ *
+ * Note that this function leaves the node in unhashed state.
+ */
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+/**
+ * hlist_add_head - add a new entry at the beginning of the hlist
+ * @n: new entry to be added
+ * @h: hlist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define hlist_entry_safe(ptr, type, member) \
+ ({ typeof(ptr) ____ptr = (ptr); \
+ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+ })
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(pos, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+ pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: a &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
+ pos && ({ n = pos->member.next; 1; }); \
+ pos = hlist_entry_safe(n, typeof(*pos), member))
+
+#endif /* LIST_H */
diff --git a/scripts/kconfig/include/list_types.h b/scripts/kconfig/include/list_types.h
new file mode 100644
index 00000000..d935b7c5
--- /dev/null
+++ b/scripts/kconfig/include/list_types.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LIST_TYPES_H
+#define LIST_TYPES_H
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#endif /* LIST_TYPES_H */
diff --git a/scripts/kconfig/include/xalloc.h b/scripts/kconfig/include/xalloc.h
new file mode 100644
index 00000000..cdadb07d
--- /dev/null
+++ b/scripts/kconfig/include/xalloc.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef XALLOC_H
+#define XALLOC_H
+
+#include <stdlib.h>
+#include <string.h>
+
+static inline void *xmalloc(size_t size)
+{
+ void *p = malloc(size);
+
+ if (!p)
+ exit(1);
+ return p;
+}
+
+static inline void *xcalloc(size_t nmemb, size_t size)
+{
+ void *p = calloc(nmemb, size);
+
+ if (!p)
+ exit(1);
+ return p;
+}
+
+static inline void *xrealloc(void *p, size_t size)
+{
+ p = realloc(p, size);
+ if (!p)
+ exit(1);
+ return p;
+}
+
+static inline char *xstrdup(const char *s)
+{
+ char *p = strdup(s);
+
+ if (!p)
+ exit(1);
+ return p;
+}
+
+static inline char *xstrndup(const char *s, size_t n)
+{
+ char *p = strndup(s, n);
+
+ if (!p)
+ exit(1);
+ return p;
+}
+
+#endif /* XALLOC_H */
diff --git a/scripts/kconfig/inputbox.c b/scripts/kconfig/inputbox.c
new file mode 100644
index 00000000..5e4a1317
--- /dev/null
+++ b/scripts/kconfig/inputbox.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * inputbox.c -- implements the input box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ * Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, " Ok ", y, x, selected == 0);
+ print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+ const char *init)
+{
+ int i, x, y, box_y, box_x, box_width;
+ int input_x = 0, key = 0, button = -1;
+ int show_x, len, pos;
+ char *instr = dialog_input_result;
+ WINDOW *dialog;
+
+ if (!init)
+ instr[0] = '\0';
+ else {
+ strncpy(instr, init, sizeof(dialog_input_result) - 1);
+ instr[sizeof(dialog_input_result) - 1] = '\0';
+ }
+
+do_resize:
+ if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGHT_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ /* Draw the input field box */
+ box_width = width - 6;
+ getyx(dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width) / 2;
+ draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+ dlg.dialog.atr, dlg.border.atr);
+
+ print_buttons(dialog, height, width, 0);
+
+ /* Set up the initial value */
+ wmove(dialog, box_y, box_x);
+ wattrset(dialog, dlg.inputbox.atr);
+
+ len = strlen(instr);
+ pos = len;
+
+ if (len >= box_width) {
+ show_x = len - box_width + 1;
+ input_x = box_width - 1;
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr[show_x + i]);
+ } else {
+ show_x = 0;
+ input_x = len;
+ waddstr(dialog, instr);
+ }
+
+ wmove(dialog, box_y, box_x + input_x);
+
+ wrefresh(dialog);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ if (button == -1) { /* Input box selected */
+ switch (key) {
+ case TAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case KEY_BACKSPACE:
+ case 8: /* ^H */
+ case 127: /* ^? */
+ if (pos) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (input_x == 0) {
+ show_x--;
+ } else
+ input_x--;
+
+ if (pos < len) {
+ for (i = pos - 1; i < len; i++) {
+ instr[i] = instr[i+1];
+ }
+ }
+
+ pos--;
+ len--;
+ instr[len] = '\0';
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ }
+ continue;
+ case KEY_LEFT:
+ if (pos > 0) {
+ if (input_x > 0) {
+ wmove(dialog, box_y, --input_x + box_x);
+ } else if (input_x == 0) {
+ show_x--;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, box_x);
+ }
+ pos--;
+ }
+ continue;
+ case KEY_RIGHT:
+ if (pos < len) {
+ if (input_x < box_width - 1) {
+ wmove(dialog, box_y, ++input_x + box_x);
+ } else if (input_x == box_width - 1) {
+ show_x++;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ }
+ pos++;
+ }
+ continue;
+ default:
+ if (key < 0x100 && isprint(key)) {
+ if (len < MAX_LEN) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (pos < len) {
+ for (i = len; i > pos; i--)
+ instr[i] = instr[i-1];
+ instr[pos] = key;
+ } else {
+ instr[len] = key;
+ }
+ pos++;
+ len++;
+ instr[len] = '\0';
+
+ if (input_x == box_width - 1) {
+ show_x++;
+ } else {
+ input_x++;
+ }
+
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ } else
+ flash(); /* Alarm user about overflow */
+ continue;
+ }
+ }
+ }
+ switch (key) {
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ return 0;
+ case 'H':
+ case 'h':
+ delwin(dialog);
+ return 1;
+ case KEY_UP:
+ case KEY_LEFT:
+ switch (button) {
+ case -1:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 0:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ case 1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ }
+ break;
+ case TAB:
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ switch (button) {
+ case -1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ case 0:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 1:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ }
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return (button == -1 ? 0 : button);
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return KEY_ESC; /* ESC pressed */
+}
diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h
new file mode 100644
index 00000000..d0ffce2d
--- /dev/null
+++ b/scripts/kconfig/internal.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+#include <hashtable.h>
+
+#define SYMBOL_HASHSIZE (1U << 14)
+
+extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE);
+
+#define for_all_symbols(sym) \
+ hash_for_each(sym_hashtable, sym, node)
+
+#define EXPR_HASHSIZE (1U << 14)
+
+extern HASHTABLE_DECLARE(expr_hashtable, EXPR_HASHSIZE);
+
+void expr_invalidate_all(void);
+
+struct menu;
+
+extern struct menu *current_menu, *current_entry;
+
+extern const char *cur_filename;
+extern int cur_lineno;
+
+#endif /* INTERNAL_H */
diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
new file mode 100644
index 00000000..6d2c92c6
--- /dev/null
+++ b/scripts/kconfig/lexer.l
@@ -0,0 +1,461 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault yylineno
+%x ASSIGN_VAL HELP STRING
+%{
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xalloc.h>
+#include "lkc.h"
+#include "preprocess.h"
+
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+/* The Kconfig file currently being parsed. */
+const char *cur_filename;
+
+/*
+ * The line number of the current statement. This does not match yylineno.
+ * yylineno is used by the lexer, while cur_lineno is used by the parser.
+ */
+int cur_lineno;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+ int yylineno;
+ const char *filename;
+ int source_lineno;
+};
+
+static 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);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ cur_filename, yylineno, chr);
+}
+%}
+
+n [A-Za-z0-9_-]
+
+%%
+ char open_quote = 0;
+
+#.* /* ignore comment */
+[ \t]* /* whitespaces */
+\\\n /* escaped new line */
+\n return T_EOL;
+"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;
+"depends" return T_DEPENDS;
+"endchoice" return T_ENDCHOICE;
+"endif" return T_ENDIF;
+"endmenu" return T_ENDMENU;
+"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;
+"prompt" return T_PROMPT;
+"range" return T_RANGE;
+"select" return T_SELECT;
+"source" return T_SOURCE;
+"string" return T_STRING;
+"transitional" return T_TRANSITIONAL;
+"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;
+\"|\' {
+ open_quote = 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);
+
+<ASSIGN_VAL>{
+ [^[:blank:]\n]+.* {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ \n { BEGIN(INITIAL); return T_EOL; }
+ .
+}
+
+<STRING>{
+ "$".* append_expanded_string(yytext);
+ [^$'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (open_quote == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ cur_filename, cur_lineno);
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ int ts, i;
+
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ cur_filename, yylineno);
+
+ if (current_buf) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+
+/* 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 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.
+ */
+ cur_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.
+ * input() returns 0 (not EOF!) when it reachs the end of file.
+ */
+ while ((c = input()) != 0) {
+ 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();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ cur_filename = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ bool recur_include = false;
+
+ buf->state = YY_CURRENT_BUFFER;
+ buf->yylineno = yylineno;
+ buf->filename = cur_filename;
+ buf->source_lineno = cur_lineno;
+ buf->parent = current_buf;
+ current_buf = buf;
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ cur_filename, cur_lineno, name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+
+ for (buf = current_buf; buf; buf = buf->parent) {
+ if (!strcmp(buf->filename, name))
+ recur_include = true;
+ }
+
+ if (recur_include) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", name);
+
+ for (buf = current_buf; buf; buf = buf->parent)
+ fprintf(stderr, " included from: %s:%d\n",
+ buf->filename, buf->source_lineno);
+ exit(1);
+ }
+
+ yylineno = 1;
+ cur_filename = file_lookup(name);
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *tmp;
+
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(current_buf->state);
+ yylineno = current_buf->yylineno;
+ cur_filename = current_buf->filename;
+ tmp = current_buf;
+ current_buf = current_buf->parent;
+ free(tmp);
+}
diff --git a/scripts/kconfig/lexer.lex.c b/scripts/kconfig/lexer.lex.c
new file mode 100644
index 00000000..4d1d0120
--- /dev/null
+++ b/scripts/kconfig/lexer.lex.c
@@ -0,0 +1,4216 @@
+#line 1 "lexer.lex.c"
+
+#line 3 "lexer.lex.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+ #define YY_LINENO_REWIND_TO(dst) \
+ do {\
+ const char *p;\
+ for ( p = yy_cp-1; p >= (dst); --p)\
+ if ( *p == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = NULL;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart ( FILE *input_file );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
+void yy_delete_buffer ( YY_BUFFER_STATE b );
+void yy_flush_buffer ( YY_BUFFER_STATE b );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state ( void );
+
+static void yyensure_buffer_stack ( void );
+static void yy_load_buffer_state ( void );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len );
+
+void *yyalloc ( yy_size_t );
+void *yyrealloc ( void *, yy_size_t );
+void yyfree ( void * );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap() (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+FILE *yyin = NULL, *yyout = NULL;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+int yylineno = 1;
+
+extern char *yytext;
+#ifdef yytext_ptr
+#undef yytext_ptr
+#endif
+#define yytext_ptr yytext
+
+static const flex_int16_t yy_nxt[][42] =
+ {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+ },
+
+ {
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 14,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 21,
+ 21, 27, 28, 29, 30, 21, 21, 31, 32, 21,
+ 33, 21, 34, 35, 36, 37, 38, 21, 39, 21,
+ 21, 40
+
+ },
+
+ {
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 14,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 21,
+ 21, 27, 28, 29, 30, 21, 21, 31, 32, 21,
+ 33, 21, 34, 35, 36, 37, 38, 21, 39, 21,
+ 21, 40
+ },
+
+ {
+ 9, 41, 42, 43, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41
+
+ },
+
+ {
+ 9, 41, 42, 43, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41
+ },
+
+ {
+ 9, 44, 45, 46, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44
+
+ },
+
+ {
+ 9, 44, 45, 46, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44
+ },
+
+ {
+ 9, 47, 47, 48, 47, 49, 47, 50, 47, 49,
+ 47, 47, 47, 47, 47, 47, 47, 47, 51, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47
+
+ },
+
+ {
+ 9, 47, 47, 48, 47, 49, 47, 50, 47, 49,
+ 47, 47, 47, 47, 47, 47, 47, 47, 51, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47
+ },
+
+ {
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+ -9, -9
+
+ },
+
+ {
+ 9, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+ -10, -10
+ },
+
+ {
+ 9, -11, 52, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11
+
+ },
+
+ {
+ 9, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12
+ },
+
+ {
+ 9, -13, -13, -13, -13, -13, -13, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, 53, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, -13, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, -13, -13, -13, -13,
+ -13, -13
+
+ },
+
+ {
+ 9, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14
+ },
+
+ {
+ 9, 54, 54, -15, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54
+
+ },
+
+ {
+ 9, -16, -16, -16, -16, -16, -16, 55, -16, -16,
+ -16, -16, -16, 55, -16, -16, -16, -16, -16, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, -16
+ },
+
+ {
+ 9, -17, -17, -17, -17, -17, -17, -17, 56, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17
+
+ },
+
+ {
+ 9, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18
+ },
+
+ {
+ 9, -19, -19, -19, -19, -19, -19, -19, -19, -19,
+ -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
+ -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
+ -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
+ -19, -19
+
+ },
+
+ {
+ 9, -20, -20, -20, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, 57, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
+ -20, -20
+ },
+
+ {
+ 9, -21, -21, -21, -21, -21, -21, 55, -21, -21,
+ -21, -21, -21, 58, -21, -21, -21, -21, -21, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -21
+
+ },
+
+ {
+ 9, -22, -22, -22, -22, -22, -22, -22, -22, -22,
+ -22, -22, -22, -22, -22, -22, 59, -22, -22, -22,
+ -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
+ -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
+ -22, -22
+ },
+
+ {
+ 9, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, 60, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23
+
+ },
+
+ {
+ 9, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24
+ },
+
+ {
+ 9, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, 61, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25
+
+ },
+
+ {
+ 9, -26, -26, 62, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26
+ },
+
+ {
+ 9, -27, -27, -27, -27, -27, -27, 55, -27, -27,
+ -27, -27, -27, 58, -27, -27, -27, -27, -27, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 63, 58, 58, 58, 58, 58, 58, 58,
+ 58, -27
+
+ },
+
+ {
+ 9, -28, -28, -28, -28, -28, -28, 55, -28, -28,
+ -28, -28, -28, 58, -28, -28, -28, -28, -28, 58,
+ 58, 58, 58, 58, 58, 58, 58, 64, 58, 58,
+ 58, 58, 65, 58, 58, 58, 58, 58, 58, 58,
+ 58, -28
+ },
+
+ {
+ 9, -29, -29, -29, -29, -29, -29, 55, -29, -29,
+ -29, -29, -29, 58, -29, -29, -29, -29, -29, 58,
+ 58, 58, 58, 58, 66, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -29
+
+ },
+
+ {
+ 9, -30, -30, -30, -30, -30, -30, 55, -30, -30,
+ -30, -30, -30, 58, -30, -30, -30, -30, -30, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 67, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -30
+ },
+
+ {
+ 9, -31, -31, -31, -31, -31, -31, 55, -31, -31,
+ -31, -31, -31, 58, -31, -31, -31, -31, -31, 58,
+ 58, 58, 58, 58, 68, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -31
+
+ },
+
+ {
+ 9, -32, -32, -32, -32, -32, -32, 55, -32, -32,
+ -32, -32, -32, 58, -32, -32, -32, -32, -32, 58,
+ 58, 58, 58, 58, 58, 69, 58, 58, 58, 58,
+ 70, 71, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -32
+ },
+
+ {
+ 9, -33, -33, -33, -33, -33, -33, 55, -33, -33,
+ -33, -33, -33, 58, -33, -33, -33, -33, -33, 58,
+ 72, 58, 58, 58, 73, 58, 58, 58, 58, 58,
+ 58, 58, 74, 58, 58, 58, 58, 58, 58, 58,
+ 58, -33
+
+ },
+
+ {
+ 9, -34, -34, -34, -34, -34, -34, 55, -34, -34,
+ -34, -34, -34, 58, -34, -34, -34, -34, -34, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 75, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -34
+ },
+
+ {
+ 9, -35, -35, -35, -35, -35, -35, 55, -35, -35,
+ -35, -35, -35, 58, -35, -35, -35, -35, -35, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 76, 58, 58, 58, 58, 58,
+ 58, -35
+
+ },
+
+ {
+ 9, -36, -36, -36, -36, -36, -36, 55, -36, -36,
+ -36, -36, -36, 58, -36, -36, -36, -36, -36, 58,
+ 77, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -36
+ },
+
+ {
+ 9, -37, -37, -37, -37, -37, -37, 55, -37, -37,
+ -37, -37, -37, 58, -37, -37, -37, -37, -37, 58,
+ 58, 58, 58, 58, 78, 58, 58, 58, 58, 58,
+ 58, 58, 79, 58, 58, 58, 80, 58, 58, 58,
+ 58, -37
+
+ },
+
+ {
+ 9, -38, -38, -38, -38, -38, -38, 55, -38, -38,
+ -38, -38, -38, 58, -38, -38, -38, -38, -38, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 81, 58, 58, 58, 58, 58,
+ 58, -38
+ },
+
+ {
+ 9, -39, -39, -39, -39, -39, -39, 55, -39, -39,
+ -39, -39, -39, 58, -39, -39, -39, -39, -39, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 82, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -39
+
+ },
+
+ {
+ 9, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, 83
+ },
+
+ {
+ 9, 84, 85, -41, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84
+
+ },
+
+ {
+ 9, -42, -42, -42, -42, -42, -42, -42, -42, -42,
+ -42, -42, -42, -42, -42, -42, -42, -42, -42, -42,
+ -42, -42, -42, -42, -42, -42, -42, -42, -42, -42,
+ -42, -42, -42, -42, -42, -42, -42, -42, -42, -42,
+ -42, -42
+ },
+
+ {
+ 9, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43
+
+ },
+
+ {
+ 9, 86, 86, -44, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86
+ },
+
+ {
+ 9, -45, 87, 88, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45
+
+ },
+
+ {
+ 9, 89, -46, -46, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89
+ },
+
+ {
+ 9, 90, 90, -47, 90, -47, 90, -47, 90, -47,
+ 90, 90, 90, 90, 90, 90, 90, 90, -47, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90
+
+ },
+
+ {
+ 9, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48
+ },
+
+ {
+ 9, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49
+
+ },
+
+ {
+ 9, 91, 91, -50, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91
+ },
+
+ {
+ 9, 92, 92, -51, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92
+
+ },
+
+ {
+ 9, -52, 52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52
+ },
+
+ {
+ 9, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53
+
+ },
+
+ {
+ 9, 54, 54, -54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54
+ },
+
+ {
+ 9, -55, -55, -55, -55, -55, -55, 55, -55, -55,
+ -55, -55, -55, 55, -55, -55, -55, -55, -55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, -55
+
+ },
+
+ {
+ 9, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, -56
+ },
+
+ {
+ 9, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57
+
+ },
+
+ {
+ 9, -58, -58, -58, -58, -58, -58, 55, -58, -58,
+ -58, -58, -58, 58, -58, -58, -58, -58, -58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -58
+ },
+
+ {
+ 9, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59
+
+ },
+
+ {
+ 9, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60
+ },
+
+ {
+ 9, -61, -61, -61, -61, -61, -61, -61, -61, -61,
+ -61, -61, -61, -61, -61, -61, -61, -61, -61, -61,
+ -61, -61, -61, -61, -61, -61, -61, -61, -61, -61,
+ -61, -61, -61, -61, -61, -61, -61, -61, -61, -61,
+ -61, -61
+
+ },
+
+ {
+ 9, -62, -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62, -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62, -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62, -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62
+ },
+
+ {
+ 9, -63, -63, -63, -63, -63, -63, 55, -63, -63,
+ -63, -63, -63, 58, -63, -63, -63, -63, -63, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 93, 58, 58, 58, 58, 58, 58, 58,
+ 58, -63
+
+ },
+
+ {
+ 9, -64, -64, -64, -64, -64, -64, 55, -64, -64,
+ -64, -64, -64, 58, -64, -64, -64, -64, -64, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 94, 58, 58, 58, 58, 58, 58, 58,
+ 58, -64
+ },
+
+ {
+ 9, -65, -65, -65, -65, -65, -65, 55, -65, -65,
+ -65, -65, -65, 58, -65, -65, -65, -65, -65, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 95, 96, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -65
+
+ },
+
+ {
+ 9, -66, -66, -66, -66, -66, -66, 55, -66, -66,
+ -66, -66, -66, 58, -66, -66, -66, -66, -66, 58,
+ 58, 58, 58, 58, 58, 97, 58, 58, 58, 58,
+ 58, 58, 58, 98, 58, 58, 58, 58, 58, 58,
+ 58, -66
+ },
+
+ {
+ 9, -67, -67, -67, -67, -67, -67, 55, -67, -67,
+ -67, -67, -67, 58, -67, -67, -67, -67, -67, 58,
+ 58, 58, 58, 99, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -67
+
+ },
+
+ {
+ 9, -68, -68, -68, -68, -68, -68, 55, -68, -68,
+ -68, -68, -68, 58, -68, -68, -68, -68, -68, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 100,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 101,
+ 58, -68
+ },
+
+ {
+ 9, -69, -69, -69, -69, -69, -69, 55, -69, -69,
+ -69, -69, -69, 58, -69, -69, -69, -69, -69, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -69
+
+ },
+
+ {
+ 9, -70, -70, -70, -70, -70, -70, 55, -70, -70,
+ -70, -70, -70, 58, -70, -70, -70, -70, -70, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 102, 58, 58, 58, 58, 58, 58,
+ 58, -70
+ },
+
+ {
+ 9, -71, -71, -71, -71, -71, -71, 55, -71, -71,
+ -71, -71, -71, 58, -71, -71, -71, -71, -71, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 103, 58, 58, 58,
+ 58, -71
+
+ },
+
+ {
+ 9, -72, -72, -72, -72, -72, -72, 55, -72, -72,
+ -72, -72, -72, 58, -72, -72, -72, -72, -72, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 104, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -72
+ },
+
+ {
+ 9, -73, -73, -73, -73, -73, -73, 55, -73, -73,
+ -73, -73, -73, 58, -73, -73, -73, -73, -73, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 105, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -73
+
+ },
+
+ {
+ 9, -74, -74, -74, -74, -74, -74, 55, -74, -74,
+ -74, -74, -74, 58, -74, -74, -74, -74, -74, 58,
+ 58, 58, 58, 106, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -74
+ },
+
+ {
+ 9, -75, -75, -75, -75, -75, -75, 55, -75, -75,
+ -75, -75, -75, 58, -75, -75, -75, -75, -75, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -75
+
+ },
+
+ {
+ 9, -76, -76, -76, -76, -76, -76, 55, -76, -76,
+ -76, -76, -76, 58, -76, -76, -76, -76, -76, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 107, 58, 58, 58, 58, 58, 58, 58,
+ 58, -76
+ },
+
+ {
+ 9, -77, -77, -77, -77, -77, -77, 55, -77, -77,
+ -77, -77, -77, 58, -77, -77, -77, -77, -77, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 108, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -77
+
+ },
+
+ {
+ 9, -78, -78, -78, -78, -78, -78, 55, -78, -78,
+ -78, -78, -78, 58, -78, -78, -78, -78, -78, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 109,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -78
+ },
+
+ {
+ 9, -79, -79, -79, -79, -79, -79, 55, -79, -79,
+ -79, -79, -79, 58, -79, -79, -79, -79, -79, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 110, 58, 58,
+ 58, -79
+
+ },
+
+ {
+ 9, -80, -80, -80, -80, -80, -80, 55, -80, -80,
+ -80, -80, -80, 58, -80, -80, -80, -80, -80, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 111, 58, 58, 58, 58, 58,
+ 58, -80
+ },
+
+ {
+ 9, -81, -81, -81, -81, -81, -81, 55, -81, -81,
+ -81, -81, -81, 58, -81, -81, -81, -81, -81, 58,
+ 112, 58, 58, 58, 58, 58, 58, 58, 113, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -81
+
+ },
+
+ {
+ 9, -82, -82, -82, -82, -82, -82, 55, -82, -82,
+ -82, -82, -82, 58, -82, -82, -82, -82, -82, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 114, 58, 58, 58, 58,
+ 58, -82
+ },
+
+ {
+ 9, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83
+
+ },
+
+ {
+ 9, 84, 85, -84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84
+ },
+
+ {
+ 9, 85, 85, -85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85
+
+ },
+
+ {
+ 9, 86, 86, -86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86
+ },
+
+ {
+ 9, -87, 87, 88, -87, -87, -87, -87, -87, -87,
+ -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+ -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+ -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+ -87, -87
+
+ },
+
+ {
+ 9, 89, -88, -88, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89
+ },
+
+ {
+ 9, -89, -89, -89, -89, -89, -89, -89, -89, -89,
+ -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
+ -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
+ -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
+ -89, -89
+
+ },
+
+ {
+ 9, 90, 90, -90, 90, -90, 90, -90, 90, -90,
+ 90, 90, 90, 90, 90, 90, 90, 90, -90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90
+ },
+
+ {
+ 9, 91, 91, -91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91
+
+ },
+
+ {
+ 9, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, -92
+ },
+
+ {
+ 9, -93, -93, -93, -93, -93, -93, 55, -93, -93,
+ -93, -93, -93, 58, -93, -93, -93, -93, -93, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 115,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -93
+
+ },
+
+ {
+ 9, -94, -94, -94, -94, -94, -94, 55, -94, -94,
+ -94, -94, -94, 58, -94, -94, -94, -94, -94, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 116, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -94
+ },
+
+ {
+ 9, -95, -95, -95, -95, -95, -95, 55, -95, -95,
+ -95, -95, -95, 58, -95, -95, -95, -95, -95, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 117, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -95
+
+ },
+
+ {
+ 9, -96, -96, -96, -96, -96, -96, 55, -96, -96,
+ -96, -96, -96, 58, -96, -96, -96, -96, -96, 58,
+ 58, 58, 58, 58, 58, 118, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -96
+ },
+
+ {
+ 9, -97, -97, -97, -97, -97, -97, 55, -97, -97,
+ -97, -97, -97, 58, -97, -97, -97, -97, -97, 119,
+ 120, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -97
+
+ },
+
+ {
+ 9, -98, -98, -98, -98, -98, -98, 55, -98, -98,
+ -98, -98, -98, 58, -98, -98, -98, -98, -98, 58,
+ 58, 58, 58, 58, 121, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -98
+ },
+
+ {
+ 9, -99, -99, -99, -99, -99, -99, 55, -99, -99,
+ -99, -99, -99, 58, -99, -99, -99, -99, -99, 58,
+ 58, 58, 122, 58, 58, 58, 58, 58, 123, 58,
+ 124, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -99
+
+ },
+
+ {
+ 9, -100, -100, -100, -100, -100, -100, 55, -100, -100,
+ -100, -100, -100, 58, -100, -100, -100, -100, -100, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 125, 58, 58, 58, 58, 58, 58,
+ 58, -100
+ },
+
+ {
+ 9, -101, -101, -101, -101, -101, -101, 55, -101, -101,
+ -101, -101, -101, 58, -101, -101, -101, -101, -101, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -101
+
+ },
+
+ {
+ 9, -102, -102, -102, -102, -102, -102, 55, -102, -102,
+ -102, -102, -102, 58, -102, -102, -102, -102, -102, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 126,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -102
+ },
+
+ {
+ 9, -103, -103, -103, -103, -103, -103, 55, -103, -103,
+ -103, -103, -103, 58, -103, -103, -103, -103, -103, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -103
+
+ },
+
+ {
+ 9, -104, -104, -104, -104, -104, -104, 55, -104, -104,
+ -104, -104, -104, 58, -104, -104, -104, -104, -104, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 127, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -104
+ },
+
+ {
+ 9, -105, -105, -105, -105, -105, -105, 55, -105, -105,
+ -105, -105, -105, 58, -105, -105, -105, -105, -105, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 128, 58, 58,
+ 58, -105
+
+ },
+
+ {
+ 9, -106, -106, -106, -106, -106, -106, 55, -106, -106,
+ -106, -106, -106, 58, -106, -106, -106, -106, -106, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 129, 58, 58,
+ 58, -106
+ },
+
+ {
+ 9, -107, -107, -107, -107, -107, -107, 55, -107, -107,
+ -107, -107, -107, 58, -107, -107, -107, -107, -107, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 130, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -107
+
+ },
+
+ {
+ 9, -108, -108, -108, -108, -108, -108, 55, -108, -108,
+ -108, -108, -108, 58, -108, -108, -108, -108, -108, 58,
+ 58, 58, 58, 58, 58, 58, 131, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -108
+ },
+
+ {
+ 9, -109, -109, -109, -109, -109, -109, 55, -109, -109,
+ -109, -109, -109, 58, -109, -109, -109, -109, -109, 58,
+ 58, 58, 58, 58, 132, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -109
+
+ },
+
+ {
+ 9, -110, -110, -110, -110, -110, -110, 55, -110, -110,
+ -110, -110, -110, 58, -110, -110, -110, -110, -110, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 133, 58, 58, 58, 58, 58,
+ 58, -110
+ },
+
+ {
+ 9, -111, -111, -111, -111, -111, -111, 55, -111, -111,
+ -111, -111, -111, 58, -111, -111, -111, -111, -111, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 134, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -111
+
+ },
+
+ {
+ 9, -112, -112, -112, -112, -112, -112, 55, -112, -112,
+ -112, -112, -112, 58, -112, -112, -112, -112, -112, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 135, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -112
+ },
+
+ {
+ 9, -113, -113, -113, -113, -113, -113, 55, -113, -113,
+ -113, -113, -113, 58, -113, -113, -113, -113, -113, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 136, 58, 58, 58, 58,
+ 58, -113
+
+ },
+
+ {
+ 9, -114, -114, -114, -114, -114, -114, 55, -114, -114,
+ -114, -114, -114, 58, -114, -114, -114, -114, -114, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 137, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -114
+ },
+
+ {
+ 9, -115, -115, -115, -115, -115, -115, 55, -115, -115,
+ -115, -115, -115, 58, -115, -115, -115, -115, -115, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -115
+
+ },
+
+ {
+ 9, -116, -116, -116, -116, -116, -116, 55, -116, -116,
+ -116, -116, -116, 58, -116, -116, -116, -116, -116, 58,
+ 58, 58, 138, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -116
+ },
+
+ {
+ 9, -117, -117, -117, -117, -117, -117, 55, -117, -117,
+ -117, -117, -117, 58, -117, -117, -117, -117, -117, 58,
+ 58, 58, 58, 58, 139, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -117
+
+ },
+
+ {
+ 9, -118, -118, -118, -118, -118, -118, 55, -118, -118,
+ -118, -118, -118, 58, -118, -118, -118, -118, -118, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 140, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -118
+ },
+
+ {
+ 9, -119, -119, -119, -119, -119, -119, 55, -119, -119,
+ -119, -119, -119, 58, -119, -119, -119, -119, -119, 58,
+ 58, 141, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 142, 58, 58, 58,
+ 58, -119
+
+ },
+
+ {
+ 9, -120, -120, -120, -120, -120, -120, 55, -120, -120,
+ -120, -120, -120, 58, -120, -120, -120, -120, -120, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 143, 58, 58,
+ 58, -120
+ },
+
+ {
+ 9, -121, -121, -121, -121, -121, -121, 55, -121, -121,
+ -121, -121, -121, 58, -121, -121, -121, -121, -121, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 144, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -121
+
+ },
+
+ {
+ 9, -122, -122, -122, -122, -122, -122, 55, -122, -122,
+ -122, -122, -122, 58, -122, -122, -122, -122, -122, 58,
+ 58, 58, 58, 58, 58, 58, 58, 145, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -122
+ },
+
+ {
+ 9, -123, -123, -123, -123, -123, -123, 55, -123, -123,
+ -123, -123, -123, 58, -123, -123, -123, -123, -123, 58,
+ 58, 58, 58, 58, 58, 146, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -123
+
+ },
+
+ {
+ 9, -124, -124, -124, -124, -124, -124, 55, -124, -124,
+ -124, -124, -124, 58, -124, -124, -124, -124, -124, 58,
+ 58, 58, 58, 58, 147, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -124
+ },
+
+ {
+ 9, -125, -125, -125, -125, -125, -125, 55, -125, -125,
+ -125, -125, -125, 58, -125, -125, -125, -125, -125, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -125
+
+ },
+
+ {
+ 9, -126, -126, -126, -126, -126, -126, 55, -126, -126,
+ -126, -126, -126, 58, -126, -126, -126, -126, -126, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 148, -126
+ },
+
+ {
+ 9, -127, -127, -127, -127, -127, -127, 55, -127, -127,
+ -127, -127, -127, 58, -127, -127, -127, -127, -127, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 149, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -127
+
+ },
+
+ {
+ 9, -128, -128, -128, -128, -128, -128, 55, -128, -128,
+ -128, -128, -128, 58, -128, -128, -128, -128, -128, 58,
+ 58, 58, 150, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -128
+ },
+
+ {
+ 9, -129, -129, -129, -129, -129, -129, 55, -129, -129,
+ -129, -129, -129, 58, -129, -129, -129, -129, -129, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 151,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -129
+
+ },
+
+ {
+ 9, -130, -130, -130, -130, -130, -130, 55, -130, -130,
+ -130, -130, -130, 58, -130, -130, -130, -130, -130, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 152, 58, 58, 58, 58, 58, 58,
+ 58, -130
+ },
+
+ {
+ 9, -131, -131, -131, -131, -131, -131, 55, -131, -131,
+ -131, -131, -131, 58, -131, -131, -131, -131, -131, 58,
+ 58, 58, 58, 58, 153, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -131
+
+ },
+
+ {
+ 9, -132, -132, -132, -132, -132, -132, 55, -132, -132,
+ -132, -132, -132, 58, -132, -132, -132, -132, -132, 58,
+ 58, 58, 154, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -132
+ },
+
+ {
+ 9, -133, -133, -133, -133, -133, -133, 55, -133, -133,
+ -133, -133, -133, 58, -133, -133, -133, -133, -133, 58,
+ 58, 58, 155, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -133
+
+ },
+
+ {
+ 9, -134, -134, -134, -134, -134, -134, 55, -134, -134,
+ -134, -134, -134, 58, -134, -134, -134, -134, -134, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 156, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -134
+ },
+
+ {
+ 9, -135, -135, -135, -135, -135, -135, 55, -135, -135,
+ -135, -135, -135, 58, -135, -135, -135, -135, -135, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 157, 58, 58, 58, 58,
+ 58, -135
+
+ },
+
+ {
+ 9, -136, -136, -136, -136, -136, -136, 55, -136, -136,
+ -136, -136, -136, 58, -136, -136, -136, -136, -136, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 158, 58, 58, 58,
+ 58, -136
+ },
+
+ {
+ 9, -137, -137, -137, -137, -137, -137, 55, -137, -137,
+ -137, -137, -137, 58, -137, -137, -137, -137, -137, 58,
+ 58, 159, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -137
+
+ },
+
+ {
+ 9, -138, -138, -138, -138, -138, -138, 55, -138, -138,
+ -138, -138, -138, 58, -138, -138, -138, -138, -138, 58,
+ 58, 58, 58, 58, 160, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -138
+ },
+
+ {
+ 9, -139, -139, -139, -139, -139, -139, 55, -139, -139,
+ -139, -139, -139, 58, -139, -139, -139, -139, -139, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 161, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -139
+
+ },
+
+ {
+ 9, -140, -140, -140, -140, -140, -140, 55, -140, -140,
+ -140, -140, -140, 58, -140, -140, -140, -140, -140, 58,
+ 58, 58, 58, 58, 58, 58, 162, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -140
+ },
+
+ {
+ 9, -141, -141, -141, -141, -141, -141, 55, -141, -141,
+ -141, -141, -141, 58, -141, -141, -141, -141, -141, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 163, 58, 58, 58, 58, 58, 58, 58,
+ 58, -141
+
+ },
+
+ {
+ 9, -142, -142, -142, -142, -142, -142, 55, -142, -142,
+ -142, -142, -142, 58, -142, -142, -142, -142, -142, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 164, 58, 58, 58, 58, 58,
+ 58, -142
+ },
+
+ {
+ 9, -143, -143, -143, -143, -143, -143, 55, -143, -143,
+ -143, -143, -143, 58, -143, -143, -143, -143, -143, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 165,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -143
+
+ },
+
+ {
+ 9, -144, -144, -144, -144, -144, -144, 55, -144, -144,
+ -144, -144, -144, 58, -144, -144, -144, -144, -144, 58,
+ 58, 58, 58, 166, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -144
+ },
+
+ {
+ 9, -145, -145, -145, -145, -145, -145, 55, -145, -145,
+ -145, -145, -145, 58, -145, -145, -145, -145, -145, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 167, 58, 58, 58, 58, 58, 58, 58,
+ 58, -145
+
+ },
+
+ {
+ 9, -146, -146, -146, -146, -146, -146, 55, -146, -146,
+ -146, -146, -146, 58, -146, -146, -146, -146, -146, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -146
+ },
+
+ {
+ 9, -147, -147, -147, -147, -147, -147, 55, -147, -147,
+ -147, -147, -147, 58, -147, -147, -147, -147, -147, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 168, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -147
+
+ },
+
+ {
+ 9, -148, -148, -148, -148, -148, -148, 55, -148, -148,
+ -148, -148, -148, 58, -148, -148, -148, -148, -148, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -148
+ },
+
+ {
+ 9, -149, -149, -149, -149, -149, -149, 55, -149, -149,
+ -149, -149, -149, 58, -149, -149, -149, -149, -149, 58,
+ 58, 58, 58, 58, 169, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -149
+
+ },
+
+ {
+ 9, -150, -150, -150, -150, -150, -150, 55, -150, -150,
+ -150, -150, -150, 58, -150, -150, -150, -150, -150, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 170, 58, 58, 58, 58, 58, 58, 58,
+ 58, -150
+ },
+
+ {
+ 9, -151, -151, -151, -151, -151, -151, 55, -151, -151,
+ -151, -151, -151, 58, -151, -151, -151, -151, -151, 58,
+ 58, 58, 58, 58, 171, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -151
+
+ },
+
+ {
+ 9, -152, -152, -152, -152, -152, -152, 55, -152, -152,
+ -152, -152, -152, 58, -152, -152, -152, -152, -152, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 172, 58, 58, 58,
+ 58, -152
+ },
+
+ {
+ 9, -153, -153, -153, -153, -153, -153, 55, -153, -153,
+ -153, -153, -153, 58, -153, -153, -153, -153, -153, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -153
+
+ },
+
+ {
+ 9, -154, -154, -154, -154, -154, -154, 55, -154, -154,
+ -154, -154, -154, 58, -154, -154, -154, -154, -154, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 173, 58, 58, 58,
+ 58, -154
+ },
+
+ {
+ 9, -155, -155, -155, -155, -155, -155, 55, -155, -155,
+ -155, -155, -155, 58, -155, -155, -155, -155, -155, 58,
+ 58, 58, 58, 58, 174, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -155
+
+ },
+
+ {
+ 9, -156, -156, -156, -156, -156, -156, 55, -156, -156,
+ -156, -156, -156, 58, -156, -156, -156, -156, -156, 58,
+ 58, 58, 58, 58, 58, 58, 175, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -156
+ },
+
+ {
+ 9, -157, -157, -157, -157, -157, -157, 55, -157, -157,
+ -157, -157, -157, 58, -157, -157, -157, -157, -157, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 176, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -157
+
+ },
+
+ {
+ 9, -158, -158, -158, -158, -158, -158, 55, -158, -158,
+ -158, -158, -158, 58, -158, -158, -158, -158, -158, 58,
+ 177, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -158
+ },
+
+ {
+ 9, -159, -159, -159, -159, -159, -159, 55, -159, -159,
+ -159, -159, -159, 58, -159, -159, -159, -159, -159, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 178,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -159
+
+ },
+
+ {
+ 9, -160, -160, -160, -160, -160, -160, 55, -160, -160,
+ -160, -160, -160, 58, -160, -160, -160, -160, -160, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -160
+ },
+
+ {
+ 9, -161, -161, -161, -161, -161, -161, 55, -161, -161,
+ -161, -161, -161, 58, -161, -161, -161, -161, -161, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 179, 58, 58, 58,
+ 58, -161
+
+ },
+
+ {
+ 9, -162, -162, -162, -162, -162, -162, 55, -162, -162,
+ -162, -162, -162, 58, -162, -162, -162, -162, -162, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -162
+ },
+
+ {
+ 9, -163, -163, -163, -163, -163, -163, 55, -163, -163,
+ -163, -163, -163, 58, -163, -163, -163, -163, -163, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 180, 58, 58, 58, 58, 58, 58, 58,
+ 58, -163
+
+ },
+
+ {
+ 9, -164, -164, -164, -164, -164, -164, 55, -164, -164,
+ -164, -164, -164, 58, -164, -164, -164, -164, -164, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 181, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -164
+ },
+
+ {
+ 9, -165, -165, -165, -165, -165, -165, 55, -165, -165,
+ -165, -165, -165, 58, -165, -165, -165, -165, -165, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 182, 58, 58, 58,
+ 58, -165
+
+ },
+
+ {
+ 9, -166, -166, -166, -166, -166, -166, 55, -166, -166,
+ -166, -166, -166, 58, -166, -166, -166, -166, -166, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 183, 58, 58, 58, 58,
+ 58, -166
+ },
+
+ {
+ 9, -167, -167, -167, -167, -167, -167, 55, -167, -167,
+ -167, -167, -167, 58, -167, -167, -167, -167, -167, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 184, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -167
+
+ },
+
+ {
+ 9, -168, -168, -168, -168, -168, -168, 55, -168, -168,
+ -168, -168, -168, 58, -168, -168, -168, -168, -168, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 185, 58, 58,
+ 58, -168
+ },
+
+ {
+ 9, -169, -169, -169, -169, -169, -169, 55, -169, -169,
+ -169, -169, -169, 58, -169, -169, -169, -169, -169, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 186, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -169
+
+ },
+
+ {
+ 9, -170, -170, -170, -170, -170, -170, 55, -170, -170,
+ -170, -170, -170, 58, -170, -170, -170, -170, -170, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 187, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -170
+ },
+
+ {
+ 9, -171, -171, -171, -171, -171, -171, 55, -171, -171,
+ -171, -171, -171, 58, -171, -171, -171, -171, -171, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 188, 58, 58, 58, 58,
+ 58, -171
+
+ },
+
+ {
+ 9, -172, -172, -172, -172, -172, -172, 55, -172, -172,
+ -172, -172, -172, 58, -172, -172, -172, -172, -172, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -172
+ },
+
+ {
+ 9, -173, -173, -173, -173, -173, -173, 55, -173, -173,
+ -173, -173, -173, 58, -173, -173, -173, -173, -173, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -173
+
+ },
+
+ {
+ 9, -174, -174, -174, -174, -174, -174, 55, -174, -174,
+ -174, -174, -174, 58, -174, -174, -174, -174, -174, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -174
+ },
+
+ {
+ 9, -175, -175, -175, -175, -175, -175, 55, -175, -175,
+ -175, -175, -175, 58, -175, -175, -175, -175, -175, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -175
+
+ },
+
+ {
+ 9, -176, -176, -176, -176, -176, -176, 55, -176, -176,
+ -176, -176, -176, 58, -176, -176, -176, -176, -176, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 189, 58, 58, 58,
+ 58, -176
+ },
+
+ {
+ 9, -177, -177, -177, -177, -177, -177, 55, -177, -177,
+ -177, -177, -177, 58, -177, -177, -177, -177, -177, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 190, 58, 58, 58,
+ 58, -177
+
+ },
+
+ {
+ 9, -178, -178, -178, -178, -178, -178, 55, -178, -178,
+ -178, -178, -178, 58, -178, -178, -178, -178, -178, 58,
+ 58, 58, 58, 58, 191, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -178
+ },
+
+ {
+ 9, -179, -179, -179, -179, -179, -179, 55, -179, -179,
+ -179, -179, -179, 58, -179, -179, -179, -179, -179, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -179
+
+ },
+
+ {
+ 9, -180, -180, -180, -180, -180, -180, 55, -180, -180,
+ -180, -180, -180, 58, -180, -180, -180, -180, -180, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 192,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -180
+ },
+
+ {
+ 9, -181, -181, -181, -181, -181, -181, 55, -181, -181,
+ -181, -181, -181, 58, -181, -181, -181, -181, -181, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 193, 58, 58, 58, 58,
+ 58, -181
+
+ },
+
+ {
+ 9, -182, -182, -182, -182, -182, -182, 55, -182, -182,
+ -182, -182, -182, 58, -182, -182, -182, -182, -182, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -182
+ },
+
+ {
+ 9, -183, -183, -183, -183, -183, -183, 55, -183, -183,
+ -183, -183, -183, 58, -183, -183, -183, -183, -183, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -183
+
+ },
+
+ {
+ 9, -184, -184, -184, -184, -184, -184, 55, -184, -184,
+ -184, -184, -184, 58, -184, -184, -184, -184, -184, 58,
+ 58, 58, 194, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -184
+ },
+
+ {
+ 9, -185, -185, -185, -185, -185, -185, 55, -185, -185,
+ -185, -185, -185, 58, -185, -185, -185, -185, -185, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -185
+
+ },
+
+ {
+ 9, -186, -186, -186, -186, -186, -186, 55, -186, -186,
+ -186, -186, -186, 58, -186, -186, -186, -186, -186, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 195, 58, 58,
+ 58, -186
+ },
+
+ {
+ 9, -187, -187, -187, -187, -187, -187, 55, -187, -187,
+ -187, -187, -187, 58, -187, -187, -187, -187, -187, 58,
+ 58, 58, 58, 58, 58, 196, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -187
+
+ },
+
+ {
+ 9, -188, -188, -188, -188, -188, -188, 55, -188, -188,
+ -188, -188, -188, 58, -188, -188, -188, -188, -188, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -188
+ },
+
+ {
+ 9, -189, -189, -189, -189, -189, -189, 55, -189, -189,
+ -189, -189, -189, 58, -189, -189, -189, -189, -189, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 197, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -189
+
+ },
+
+ {
+ 9, -190, -190, -190, -190, -190, -190, 55, -190, -190,
+ -190, -190, -190, 58, -190, -190, -190, -190, -190, 58,
+ 58, 58, 58, 58, 198, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -190
+ },
+
+ {
+ 9, -191, -191, -191, -191, -191, -191, 55, -191, -191,
+ -191, -191, -191, 58, -191, -191, -191, -191, -191, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -191
+
+ },
+
+ {
+ 9, -192, -192, -192, -192, -192, -192, 55, -192, -192,
+ -192, -192, -192, 58, -192, -192, -192, -192, -192, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -192
+ },
+
+ {
+ 9, -193, -193, -193, -193, -193, -193, 55, -193, -193,
+ -193, -193, -193, 58, -193, -193, -193, -193, -193, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 199, 58, 58, 58,
+ 58, -193
+
+ },
+
+ {
+ 9, -194, -194, -194, -194, -194, -194, 55, -194, -194,
+ -194, -194, -194, 58, -194, -194, -194, -194, -194, 58,
+ 58, 58, 58, 58, 200, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -194
+ },
+
+ {
+ 9, -195, -195, -195, -195, -195, -195, 55, -195, -195,
+ -195, -195, -195, 58, -195, -195, -195, -195, -195, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -195
+
+ },
+
+ {
+ 9, -196, -196, -196, -196, -196, -196, 55, -196, -196,
+ -196, -196, -196, 58, -196, -196, -196, -196, -196, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 201, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -196
+ },
+
+ {
+ 9, -197, -197, -197, -197, -197, -197, 55, -197, -197,
+ -197, -197, -197, 58, -197, -197, -197, -197, -197, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 202, 58, 58, 58, 58, 58, 58, 58,
+ 58, -197
+
+ },
+
+ {
+ 9, -198, -198, -198, -198, -198, -198, 55, -198, -198,
+ -198, -198, -198, 58, -198, -198, -198, -198, -198, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -198
+ },
+
+ {
+ 9, -199, -199, -199, -199, -199, -199, 55, -199, -199,
+ -199, -199, -199, 58, -199, -199, -199, -199, -199, 58,
+ 203, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -199
+
+ },
+
+ {
+ 9, -200, -200, -200, -200, -200, -200, 55, -200, -200,
+ -200, -200, -200, 58, -200, -200, -200, -200, -200, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -200
+ },
+
+ {
+ 9, -201, -201, -201, -201, -201, -201, 55, -201, -201,
+ -201, -201, -201, 58, -201, -201, -201, -201, -201, 58,
+ 58, 58, 58, 58, 58, 58, 204, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -201
+
+ },
+
+ {
+ 9, -202, -202, -202, -202, -202, -202, 55, -202, -202,
+ -202, -202, -202, 58, -202, -202, -202, -202, -202, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 205, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -202
+ },
+
+ {
+ 9, -203, -203, -203, -203, -203, -203, 55, -203, -203,
+ -203, -203, -203, 58, -203, -203, -203, -203, -203, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 206, 58, 58, 58,
+ 58, -203
+
+ },
+
+ {
+ 9, -204, -204, -204, -204, -204, -204, 55, -204, -204,
+ -204, -204, -204, 58, -204, -204, -204, -204, -204, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -204
+ },
+
+ {
+ 9, -205, -205, -205, -205, -205, -205, 55, -205, -205,
+ -205, -205, -205, 58, -205, -205, -205, -205, -205, 58,
+ 207, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -205
+
+ },
+
+ {
+ 9, -206, -206, -206, -206, -206, -206, 55, -206, -206,
+ -206, -206, -206, 58, -206, -206, -206, -206, -206, 58,
+ 58, 58, 58, 58, 208, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -206
+ },
+
+ {
+ 9, -207, -207, -207, -207, -207, -207, 55, -207, -207,
+ -207, -207, -207, 58, -207, -207, -207, -207, -207, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 209,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -207
+
+ },
+
+ {
+ 9, -208, -208, -208, -208, -208, -208, 55, -208, -208,
+ -208, -208, -208, 58, -208, -208, -208, -208, -208, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -208
+ },
+
+ {
+ 9, -209, -209, -209, -209, -209, -209, 55, -209, -209,
+ -209, -209, -209, 58, -209, -209, -209, -209, -209, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, -209
+
+ },
+
+ } ;
+
+static yy_state_type yy_get_previous_state ( void );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state );
+static int yy_get_next_buffer ( void );
+static void yynoreturn yy_fatal_error ( const char* msg );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+#define YY_NUM_RULES 63
+#define YY_END_OF_BUFFER 64
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[210] =
+ { 0,
+ 2, 2, 0, 0, 0, 0, 0, 0, 64, 50,
+ 2, 4, 42, 47, 1, 49, 50, 43, 44, 50,
+ 48, 50, 38, 36, 40, 50, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 50,
+ 51, 53, 52, 62, 59, 61, 55, 58, 57, 54,
+ 56, 2, 37, 1, 49, 35, 46, 48, 45, 39,
+ 41, 3, 48, 48, 48, 48, 48, 48, 18, 48,
+ 48, 48, 48, 48, 25, 48, 48, 48, 48, 48,
+ 48, 48, 34, 51, 51, 62, 59, 61, 60, 55,
+ 54, 56, 48, 48, 48, 48, 48, 48, 48, 48,
+
+ 17, 48, 20, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 5, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 16, 48, 48, 22, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 14, 48, 19, 48, 48,
+ 48, 48, 27, 48, 48, 48, 48, 48, 48, 6,
+ 48, 8, 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 26, 28, 29, 30, 48, 48, 48, 7, 48,
+ 48, 11, 12, 48, 15, 48, 48, 24, 48, 48,
+ 33, 9, 48, 48, 21, 48, 48, 32, 48, 13,
+
+ 48, 48, 48, 23, 48, 48, 48, 10, 31
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 7, 1, 8, 9, 10,
+ 11, 1, 12, 1, 13, 1, 1, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 14, 1, 15,
+ 16, 17, 1, 1, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 18, 1, 1, 19, 1, 20, 21, 22, 23,
+
+ 24, 25, 26, 27, 28, 13, 13, 29, 30, 31,
+ 32, 33, 13, 34, 35, 36, 37, 38, 13, 39,
+ 40, 13, 1, 41, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static const flex_int32_t yy_rule_can_match_eol[64] =
+ { 0,
+0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, };
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer.l"
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#line 9 "lexer.l"
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xalloc.h>
+#include "lkc.h"
+#include "preprocess.h"
+
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+/* The Kconfig file currently being parsed. */
+const char *cur_filename;
+
+/*
+ * The line number of the current statement. This does not match yylineno.
+ * yylineno is used by the lexer, while cur_lineno is used by the parser.
+ */
+int cur_lineno;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+ int yylineno;
+ const char *filename;
+ int source_lineno;
+};
+
+static 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);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ cur_filename, yylineno, chr);
+}
+#line 2344 "lexer.lex.c"
+#line 2345 "lexer.lex.c"
+
+#define INITIAL 0
+#define ASSIGN_VAL 1
+#define HELP 2
+#define STRING 3
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals ( void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( void );
+
+int yyget_debug ( void );
+
+void yyset_debug ( int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra ( void );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in ( void );
+
+void yyset_in ( FILE * _in_str );
+
+FILE *yyget_out ( void );
+
+void yyset_out ( FILE * _out_str );
+
+ yy_size_t yyget_leng ( void );
+
+char *yyget_text ( void );
+
+int yyget_lineno ( void );
+
+void yyset_lineno ( int _line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( void );
+#else
+extern int yywrap ( void );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr );
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * );
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( void );
+#else
+static int input ( void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ errno=0; \
+ while ( (result = (int) read( fileno(yyin), buf, (yy_size_t) max_size )) < 0 ) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ {
+#line 96 "lexer.l"
+
+#line 98 "lexer.l"
+ char open_quote = 0;
+
+#line 2554 "lexer.lex.c"
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
+ ++yy_cp;
+
+ yy_current_state = -yy_current_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ yylineno++;
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 100 "lexer.l"
+/* ignore comment */
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 101 "lexer.l"
+/* whitespaces */
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 102 "lexer.l"
+/* escaped new line */
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 103 "lexer.l"
+return T_EOL;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 104 "lexer.l"
+return T_BOOL;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 105 "lexer.l"
+return T_CHOICE;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 106 "lexer.l"
+return T_COMMENT;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 107 "lexer.l"
+return T_CONFIG;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 108 "lexer.l"
+return T_DEF_BOOL;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 109 "lexer.l"
+return T_DEF_TRISTATE;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 110 "lexer.l"
+return T_DEFAULT;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 111 "lexer.l"
+return T_DEPENDS;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 112 "lexer.l"
+return T_ENDCHOICE;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 113 "lexer.l"
+return T_ENDIF;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 114 "lexer.l"
+return T_ENDMENU;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 115 "lexer.l"
+return T_HELP;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 116 "lexer.l"
+return T_HEX;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 117 "lexer.l"
+return T_IF;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 118 "lexer.l"
+return T_IMPLY;
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 119 "lexer.l"
+return T_INT;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 120 "lexer.l"
+return T_MAINMENU;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 121 "lexer.l"
+return T_MENU;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 122 "lexer.l"
+return T_MENUCONFIG;
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 123 "lexer.l"
+return T_MODULES;
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 124 "lexer.l"
+return T_ON;
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 125 "lexer.l"
+return T_PROMPT;
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 126 "lexer.l"
+return T_RANGE;
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 127 "lexer.l"
+return T_SELECT;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 128 "lexer.l"
+return T_SOURCE;
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 129 "lexer.l"
+return T_STRING;
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 130 "lexer.l"
+return T_TRANSITIONAL;
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 131 "lexer.l"
+return T_TRISTATE;
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 132 "lexer.l"
+return T_VISIBLE;
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 133 "lexer.l"
+return T_OR;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 134 "lexer.l"
+return T_AND;
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 135 "lexer.l"
+return T_EQUAL;
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 136 "lexer.l"
+return T_UNEQUAL;
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 137 "lexer.l"
+return T_LESS;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 138 "lexer.l"
+return T_LESS_EQUAL;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 139 "lexer.l"
+return T_GREATER;
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 140 "lexer.l"
+return T_GREATER_EQUAL;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 141 "lexer.l"
+return T_NOT;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 142 "lexer.l"
+return T_OPEN_PAREN;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 143 "lexer.l"
+return T_CLOSE_PAREN;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 144 "lexer.l"
+return T_COLON_EQUAL;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 145 "lexer.l"
+return T_PLUS_EQUAL;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 146 "lexer.l"
+{
+ open_quote = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 151 "lexer.l"
+{
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 156 "lexer.l"
+{
+ /* this token includes at least one '$' */
+ yylval.string = expand_token(yytext, yyleng);
+ if (strlen(yylval.string))
+ return T_WORD;
+ free(yylval.string);
+ }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 163 "lexer.l"
+warn_ignored_character(*yytext);
+ YY_BREAK
+
+case 51:
+YY_RULE_SETUP
+#line 166 "lexer.l"
+{
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ YY_BREAK
+case 52:
+/* rule 52 can match eol */
+YY_RULE_SETUP
+#line 171 "lexer.l"
+{ BEGIN(INITIAL); return T_EOL; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 172 "lexer.l"
+
+ YY_BREAK
+
+
+case 54:
+YY_RULE_SETUP
+#line 176 "lexer.l"
+append_expanded_string(yytext);
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 177 "lexer.l"
+{
+ append_string(yytext, yyleng);
+ }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 180 "lexer.l"
+{
+ append_string(yytext + 1, yyleng - 1);
+ }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 183 "lexer.l"
+{
+ if (open_quote == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ YY_BREAK
+case 58:
+/* rule 58 can match eol */
+YY_RULE_SETUP
+#line 191 "lexer.l"
+{
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ cur_filename, cur_lineno);
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+#line 200 "lexer.l"
+{
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+
+
+case 59:
+YY_RULE_SETUP
+#line 208 "lexer.l"
+{
+ int ts, i;
+
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ YY_BREAK
+case 60:
+/* rule 60 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+YY_LINENO_REWIND_TO(yy_cp - 1);
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 232 "lexer.l"
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+case 61:
+/* rule 61 can match eol */
+YY_RULE_SETUP
+#line 236 "lexer.l"
+{
+ append_string("\n", 1);
+ }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 239 "lexer.l"
+{
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ YY_BREAK
+case YY_STATE_EOF(HELP):
+#line 249 "lexer.l"
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(ASSIGN_VAL):
+#line 255 "lexer.l"
+{
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ cur_filename, yylineno);
+
+ if (current_buf) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 270 "lexer.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 3032 "lexer.lex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = (yytext_ptr);
+ int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ int yy_is_jam;
+
+ yy_current_state = yy_nxt[yy_current_state][1];
+ yy_is_jam = (yy_current_state <= 0);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp )
+{
+ char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ yy_size_t number_to_move = (yy_n_chars) + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' ){
+ --yylineno;
+ }
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return 0;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ if ( c == '\n' )
+
+ yylineno++;
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf );
+
+ yyfree( (void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr )
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg )
+{
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yy_size_t yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ *
+ */
+void yyset_lineno (int _line_number )
+{
+
+ yylineno = _line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str )
+{
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str )
+{
+ yyout = _out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug )
+{
+ yy_flex_debug = _bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ /* We do not touch yylineno unless the option is enabled. */
+ yylineno = 1;
+
+ (yy_buffer_stack) = NULL;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = NULL;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n )
+{
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s )
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 270 "lexer.l"
+
+
+/* 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 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.
+ */
+ cur_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.
+ * input() returns 0 (not EOF!) when it reachs the end of file.
+ */
+ while ((c = input()) != 0) {
+ 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();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ cur_filename = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ bool recur_include = false;
+
+ buf->state = YY_CURRENT_BUFFER;
+ buf->yylineno = yylineno;
+ buf->filename = cur_filename;
+ buf->source_lineno = cur_lineno;
+ buf->parent = current_buf;
+ current_buf = buf;
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ cur_filename, cur_lineno, name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+
+ for (buf = current_buf; buf; buf = buf->parent) {
+ if (!strcmp(buf->filename, name))
+ recur_include = true;
+ }
+
+ if (recur_include) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", name);
+
+ for (buf = current_buf; buf; buf = buf->parent)
+ fprintf(stderr, " included from: %s:%d\n",
+ buf->filename, buf->source_lineno);
+ exit(1);
+ }
+
+ yylineno = 1;
+ cur_filename = file_lookup(name);
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *tmp;
+
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(current_buf->state);
+ yylineno = current_buf->yylineno;
+ cur_filename = current_buf->filename;
+ tmp = current_buf;
+ current_buf = current_buf->parent;
+ free(tmp);
+}
+
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
new file mode 100644
index 00000000..56548efc
--- /dev/null
+++ b/scripts/kconfig/lkc.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "expr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lkc_proto.h"
+
+#define SRCTREE "srctree"
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+static inline const char *CONFIG_prefix(void)
+{
+ return getenv( "CONFIG_" ) ?: CONFIG_;
+}
+#undef CONFIG_
+#define CONFIG_ CONFIG_prefix()
+
+extern int yylineno;
+void zconfdump(FILE *out);
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+
+/* confdata.c */
+extern struct gstr autoconf_cmd;
+const char *conf_get_configname(void);
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+ assert(len != 0);
+
+ if (fwrite(str, len, count, out) != count)
+ fprintf(stderr, "Error in writing or end of file.\n");
+}
+
+/* util.c */
+const char *file_lookup(const char *name);
+
+/* lexer.l */
+int yylex(void);
+
+struct gstr {
+ size_t len;
+ char *s;
+ /*
+ * when max_width is not zero long lines in string s (if any) get
+ * wrapped not to exceed the max_width value
+ */
+ int max_width;
+};
+struct gstr str_new(void);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+char *str_get(const struct gstr *gs);
+
+/* menu.c */
+struct menu *menu_next(struct menu *menu, struct menu *root);
+#define menu_for_each_sub_entry(menu, root) \
+ for (menu = menu_next(root, root); menu; menu = menu_next(menu, root))
+#define menu_for_each_entry(menu) \
+ menu_for_each_sub_entry(menu, &rootmenu)
+void _menu_init(void);
+void menu_warn(const struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym, enum menu_type type);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, const 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_finalize(void);
+void menu_set_type(int type);
+
+extern struct menu rootmenu;
+
+bool menu_is_empty(struct menu *menu);
+bool menu_is_visible(struct menu *menu);
+bool menu_has_prompt(const struct menu *menu);
+const char *menu_get_prompt(const struct menu *menu);
+struct menu *menu_get_parent_menu(struct menu *menu);
+struct menu *menu_get_menu_or_parent_menu(struct menu *menu);
+int get_jump_key_char(void);
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
+void menu_get_ext_help(struct menu *menu, struct gstr *help);
+void menu_dump(void);
+
+/* symbol.c */
+void sym_clear_all_valid(void);
+struct symbol *sym_choice_default(struct menu *choice);
+struct symbol *sym_calc_choice(struct menu *choice);
+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 symbol *prop_get_symbol(const struct property *prop);
+
+static inline tristate sym_get_tristate_value(const struct symbol *sym)
+{
+ return sym->curr.tri;
+}
+
+static inline bool sym_is_choice(const struct symbol *sym)
+{
+ /* A choice is a symbol with no name */
+ return sym->name == NULL;
+}
+
+bool sym_is_choice_value(const struct symbol *sym);
+
+static inline bool sym_has_value(const struct symbol *sym)
+{
+ return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
new file mode 100644
index 00000000..8914b4e8
--- /dev/null
+++ b/scripts/kconfig/lkc_proto.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LKC_PROTO_H
+#define LKC_PROTO_H
+
+#include <stdarg.h>
+
+/* confdata.c */
+void conf_parse(const char *name);
+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(int overwrite);
+void conf_set_changed(bool val);
+bool conf_get_changed(void);
+void conf_set_changed_callback(void (*fn)(bool));
+void conf_set_message_callback(void (*fn)(const char *s));
+bool conf_errors(void);
+
+/* symbol.c */
+struct symbol * sym_lookup(const char *name, int flags);
+struct symbol * sym_find(const char *name);
+void print_symbol_for_listconfig(struct symbol *sym);
+struct symbol ** sym_re_search(const char *pattern);
+const char * sym_type_name(enum symbol_type type);
+void sym_calc_value(struct symbol *sym);
+bool sym_dep_errors(void);
+enum symbol_type sym_get_type(const struct symbol *sym);
+bool sym_tristate_within_range(const struct symbol *sym, tristate tri);
+bool sym_set_tristate_value(struct symbol *sym,tristate tri);
+void choice_set_value(struct menu *choice, struct symbol *sym);
+tristate sym_toggle_tristate_value(struct symbol *sym);
+bool sym_string_valid(struct symbol *sym, const char *newval);
+bool sym_string_within_range(struct symbol *sym, const char *str);
+bool sym_set_string_value(struct symbol *sym, const char *newval);
+bool sym_is_changeable(const struct symbol *sym);
+struct menu *sym_get_prompt_menu(const struct symbol *sym);
+struct menu *sym_get_choice_menu(const struct symbol *sym);
+const char * sym_get_string_value(struct symbol *sym);
+
+const char * prop_get_type_name(enum prop_type type);
+
+/* expr.c */
+void expr_print(const struct expr *e,
+ void (*fn)(void *, struct symbol *, const char *),
+ void *data, int prevtoken);
+
+#endif /* LKC_PROTO_H */
diff --git a/scripts/kconfig/lutil.c b/scripts/kconfig/lutil.c
new file mode 100644
index 00000000..b34000be
--- /dev/null
+++ b/scripts/kconfig/lutil.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * util.c
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+ dlg.title.atr = A_BOLD;
+ dlg.button_active.atr = A_REVERSE;
+ dlg.button_inactive.atr = A_DIM;
+ dlg.button_key_active.atr = A_REVERSE;
+ dlg.button_key_inactive.atr = A_BOLD;
+ dlg.button_label_active.atr = A_REVERSE;
+ dlg.position_indicator.atr = A_BOLD;
+ dlg.item_selected.atr = A_REVERSE;
+ dlg.tag.atr = A_BOLD;
+ dlg.tag_selected.atr = A_REVERSE;
+ dlg.tag_key.atr = A_BOLD;
+ dlg.tag_key_selected.atr = A_REVERSE;
+ dlg.check.atr = A_BOLD;
+ dlg.check_selected.atr = A_REVERSE;
+ dlg.uarrow.atr = A_BOLD;
+ dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do { \
+ dlg.dialog.fg = (f); \
+ dlg.dialog.bg = (b); \
+ dlg.dialog.hl = (h); \
+} while (0)
+
+static void set_classic_theme(void)
+{
+ DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
+ DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
+ DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
+ DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
+ DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
+}
+
+static void set_blackbg_theme(void)
+{
+ DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+ DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
+ DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
+ DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false);
+
+ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
+
+ DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
+
+ DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
+
+ DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+ set_classic_theme();
+ DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+ int use_color = 1;
+ if (!theme)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "classic") == 0)
+ set_classic_theme();
+ else if (strcmp(theme, "bluetitle") == 0)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "blackbg") == 0)
+ set_blackbg_theme();
+ else if (strcmp(theme, "mono") == 0)
+ use_color = 0;
+
+ return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+ static int pair = 0;
+
+ pair++;
+ init_pair(pair, color->fg, color->bg);
+ if (color->hl)
+ color->atr = A_BOLD | COLOR_PAIR(pair);
+ else
+ color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+ init_one_color(&dlg.screen);
+ init_one_color(&dlg.shadow);
+ init_one_color(&dlg.dialog);
+ init_one_color(&dlg.title);
+ init_one_color(&dlg.border);
+ init_one_color(&dlg.button_active);
+ init_one_color(&dlg.button_inactive);
+ init_one_color(&dlg.button_key_active);
+ init_one_color(&dlg.button_key_inactive);
+ init_one_color(&dlg.button_label_active);
+ init_one_color(&dlg.button_label_inactive);
+ init_one_color(&dlg.inputbox);
+ init_one_color(&dlg.position_indicator);
+ init_one_color(&dlg.menubox);
+ init_one_color(&dlg.menubox_border);
+ init_one_color(&dlg.item);
+ init_one_color(&dlg.item_selected);
+ init_one_color(&dlg.tag);
+ init_one_color(&dlg.tag_selected);
+ init_one_color(&dlg.tag_key);
+ init_one_color(&dlg.tag_key_selected);
+ init_one_color(&dlg.check);
+ init_one_color(&dlg.check_selected);
+ init_one_color(&dlg.uarrow);
+ init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+ int use_color;
+
+ use_color = set_theme(theme);
+ if (use_color && has_colors()) {
+ start_color();
+ init_dialog_colors();
+ } else
+ set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+ int i, j;
+
+ wattrset(win, attr);
+ for (i = 0; i < height; i++) {
+ wmove(win, i, 0);
+ for (j = 0; j < width; j++)
+ waddch(win, ' ');
+ }
+ touchwin(win);
+}
+
+void dialog_clear(void)
+{
+ int lines, columns;
+
+ lines = getmaxy(stdscr);
+ columns = getmaxx(stdscr);
+
+ attr_clear(stdscr, lines, columns, dlg.screen.atr);
+ /* Display background title if it exists ... - SLH */
+ if (dlg.backtitle != NULL) {
+ int i, len = 0, skip = 0;
+ struct subtitle_list *pos;
+
+ wattrset(stdscr, dlg.screen.atr);
+ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+
+ for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+ /* 3 is for the arrow and spaces */
+ len += strlen(pos->text) + 3;
+ }
+
+ wmove(stdscr, 1, 1);
+ if (len > columns - 2) {
+ const char *ellipsis = "[...] ";
+ waddstr(stdscr, ellipsis);
+ skip = len - (columns - 2 - strlen(ellipsis));
+ }
+
+ for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+ if (skip == 0)
+ waddch(stdscr, ACS_RARROW);
+ else
+ skip--;
+
+ if (skip == 0)
+ waddch(stdscr, ' ');
+ else
+ skip--;
+
+ if (skip < strlen(pos->text)) {
+ waddstr(stdscr, pos->text + skip);
+ skip = 0;
+ } else
+ skip -= strlen(pos->text);
+
+ if (skip == 0)
+ waddch(stdscr, ' ');
+ else
+ skip--;
+ }
+
+ for (i = len + 1; i < columns - 1; i++)
+ waddch(stdscr, ACS_HLINE);
+ }
+ wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+ int height, width;
+
+ initscr(); /* Init curses */
+
+ /* Get current cursor position for signal handler in mconf.c */
+ getyx(stdscr, saved_y, saved_x);
+
+ getmaxyx(stdscr, height, width);
+ if (height < WINDOW_HEIGHT_MIN || width < WINDOW_WIDTH_MIN) {
+ endwin();
+ return -ERRDISPLAYTOOSMALL;
+ }
+
+ dlg.backtitle = backtitle;
+ color_setup(getenv("MENUCONFIG_COLOR"));
+
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+ dialog_clear();
+
+ return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+ dlg.backtitle = backtitle;
+}
+
+void set_dialog_subtitles(struct subtitle_list *subtitles)
+{
+ dlg.subtitles = subtitles;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+ /* move cursor back to original position */
+ move(y, x);
+ refresh();
+ endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+ if (title) {
+ int tlen = MIN(width - 2, strlen(title));
+ wattrset(dialog, dlg.title.atr);
+ mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+ mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+ waddch(dialog, ' ');
+ }
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are properly processed. We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+ int newl, cur_x, cur_y;
+ int prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
+
+ snprintf(tempstr, sizeof(tempstr), "%s", prompt);
+ prompt_len = strlen(tempstr);
+
+ if (prompt_len <= width - x * 2) { /* If prompt is short */
+ wmove(win, y, (width - prompt_len) / 2);
+ waddstr(win, tempstr);
+ } else {
+ cur_x = x;
+ cur_y = y;
+ newl = 1;
+ word = tempstr;
+ while (word && *word) {
+ sp = strpbrk(word, "\n ");
+ if (sp && *sp == '\n')
+ newline_separator = sp;
+
+ if (sp)
+ *sp++ = 0;
+
+ /* Wrap to next line if either the word does not fit,
+ or it is the first word of a new sentence, and it is
+ short, and the next word does not fit. */
+ room = width - cur_x;
+ wlen = strlen(word);
+ if (wlen > room ||
+ (newl && wlen < 4 && sp
+ && wlen + 1 + strlen(sp) > room
+ && (!(sp2 = strpbrk(sp, "\n "))
+ || wlen + 1 + (sp2 - sp) > room))) {
+ cur_y++;
+ cur_x = x;
+ }
+ wmove(win, cur_y, cur_x);
+ waddstr(win, word);
+ getyx(win, cur_y, cur_x);
+
+ /* Move to the next line if the word separator was a newline */
+ if (newline_separator) {
+ cur_y++;
+ cur_x = x;
+ newline_separator = 0;
+ } else
+ cur_x++;
+
+ if (sp && *sp == ' ') {
+ cur_x++; /* double space */
+ while (*++sp == ' ') ;
+ newl = 1;
+ } else
+ newl = 0;
+ word = sp;
+ }
+ }
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+ int i, temp;
+
+ wmove(win, y, x);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, "<");
+ temp = strspn(label, " ");
+ label += temp;
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ for (i = 0; i < temp; i++)
+ waddch(win, ' ');
+ wattrset(win, selected ? dlg.button_key_active.atr
+ : dlg.button_key_inactive.atr);
+ waddch(win, label[0]);
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ waddstr(win, (char *)label + 1);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, ">");
+ wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+ chtype box, chtype border)
+{
+ int i, j;
+
+ wattrset(win, 0);
+ for (i = 0; i < height; i++) {
+ wmove(win, y + i, x);
+ for (j = 0; j < width; j++)
+ if (!i && !j)
+ waddch(win, border | ACS_ULCORNER);
+ else if (i == height - 1 && !j)
+ waddch(win, border | ACS_LLCORNER);
+ else if (!i && j == width - 1)
+ waddch(win, box | ACS_URCORNER);
+ else if (i == height - 1 && j == width - 1)
+ waddch(win, box | ACS_LRCORNER);
+ else if (!i)
+ waddch(win, border | ACS_HLINE);
+ else if (i == height - 1)
+ waddch(win, box | ACS_HLINE);
+ else if (!j)
+ waddch(win, border | ACS_VLINE);
+ else if (j == width - 1)
+ waddch(win, box | ACS_VLINE);
+ else
+ waddch(win, box | ' ');
+ }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+ int i;
+
+ if (has_colors()) { /* Whether terminal supports color? */
+ wattrset(win, dlg.shadow.atr);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ waddch(win, winch(win) & A_CHARTEXT);
+ for (i = y + 1; i < y + height + 1; i++) {
+ wmove(win, i, x + width);
+ waddch(win, winch(win) & A_CHARTEXT);
+ waddch(win, winch(win) & A_CHARTEXT);
+ }
+ wnoutrefresh(win);
+ }
+}
+
+/*
+ * Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+ int i, in_paren = 0, c;
+
+ for (i = 0; i < strlen(string); i++) {
+ c = tolower(string[i]);
+
+ if (strchr("<[(", c))
+ ++in_paren;
+ if (strchr(">])", c) && in_paren > 0)
+ --in_paren;
+
+ if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and that's
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+ int key;
+ int key2;
+ int key3;
+
+ nodelay(win, TRUE);
+ keypad(win, FALSE);
+ key = wgetch(win);
+ key2 = wgetch(win);
+ do {
+ key3 = wgetch(win);
+ } while (key3 != ERR);
+ nodelay(win, FALSE);
+ keypad(win, TRUE);
+ if (key == KEY_ESC && key2 == ERR)
+ return KEY_ESC;
+ else if (key != ERR && key != KEY_ESC && key2 == ERR)
+ ungetch(key);
+
+ return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+ dialog_clear();
+ return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+ struct dialog_list *p, *next;
+
+ for (p = item_head; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ item_head = NULL;
+ item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+ va_list ap;
+ struct dialog_list *p = malloc(sizeof(*p));
+
+ if (item_head)
+ item_cur->next = p;
+ else
+ item_head = p;
+ item_cur = p;
+ memset(p, 0, sizeof(*p));
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+ va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ size_t avail;
+
+ avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+ avail, fmt, ap);
+ item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+ va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+ item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+ item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+ item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+ item_foreach()
+ if (item_is_selected())
+ return 1;
+ return 0;
+}
+
+void *item_data(void)
+{
+ return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+ return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next)
+ n++;
+ return n;
+}
+
+void item_set(int n)
+{
+ int i = 0;
+ item_foreach()
+ if (i++ == n)
+ return;
+}
+
+int item_n(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next) {
+ if (p == item_cur)
+ return n;
+ n++;
+ }
+ return 0;
+}
+
+const char *item_str(void)
+{
+ return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+ return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+ return (item_cur->node.tag == tag);
+}
diff --git a/scripts/kconfig/makefile b/scripts/kconfig/makefile
new file mode 100644
index 00000000..6bfd24a1
--- /dev/null
+++ b/scripts/kconfig/makefile
@@ -0,0 +1,44 @@
+CC ?= gcc
+LEX ?= flex
+YACC ?= bison
+
+VPATH := $(srctree)/scripts/kconfig
+
+CFLAGS := -Iinclude
+LDFLAGS := -lncurses
+
+common-obj := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \
+ preprocess.o symbol.o util.o
+
+lxdl-obj := checklist.o inputbox.o menubox.o \
+ textbox.o lutil.o yesno.o \
+ mnconf-common.o
+
+conf: conf.o $(common-obj)
+mconf: mconf.o $(common-obj) $(lxdl-obj)
+nconf: nconf.o nconf.gui.o mnconf-common.o $(common-obj)
+lexer.lex.c: lexer.l
+parser.tab.c parser.tab.h: parser.y
+
+%.lex.c: %.l
+ $(LEX) -o $@ $<
+
+parser.tab.c parser.tab.h: parser.y
+ $(YACC) -d -o parser.tab.c $<
+
+syncconfig: conf
+ scripts/kconfig/conf --syncconfig Kconfig .config
+
+menuconfig: mconf
+ scripts/kconfig/mconf Kconfig
+
+clean:
+ rm -f *.o lexer.lex.c parser.tab.c parser.tab.h conf mconf nconf
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%: %.o
+ $(CC) $(LDFLAGS) -o $@ $?
+
+.PHONY: menuconfig syncconfig clean
diff --git a/scripts/kconfig/mconf b/scripts/kconfig/mconf
new file mode 100755
index 00000000..094a28b5
--- /dev/null
+++ b/scripts/kconfig/mconf
Binary files differ
diff --git a/scripts/kconfig/mconf-cflags b/scripts/kconfig/mconf-cflags
new file mode 100644
index 00000000..f14ac568
--- /dev/null
+++ b/scripts/kconfig/mconf-cflags
@@ -0,0 +1 @@
+-D_BSD_SOURCE -DNCURSES_WIDECHAR
diff --git a/scripts/kconfig/mconf-libs b/scripts/kconfig/mconf-libs
new file mode 100644
index 00000000..4d137838
--- /dev/null
+++ b/scripts/kconfig/mconf-libs
@@ -0,0 +1 @@
+-lncursesw
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
new file mode 100644
index 00000000..9ccf9fa1
--- /dev/null
+++ b/scripts/kconfig/mconf.c
@@ -0,0 +1,940 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include "dialog.h"
+#include "lkc.h"
+#include "mnconf-common.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <list.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <xalloc.h>
+
+static const char mconf_readme[] = "Overview\n"
+ "--------\n"
+ "This interface lets you select features and parameters for the build.\n"
+ "Features can either be built-in, modularized, or ignored. Parameters\n"
+ "must be entered in as decimal or hexadecimal numbers or text.\n"
+ "\n"
+ "Menu items beginning with following braces represent features that\n"
+ " [ ] can be built in or removed\n"
+ " < > can be built in, modularized or removed\n"
+ " { } can be built in or modularized (selected by other feature)\n"
+ " - - are selected by other feature,\n"
+ "while *, M or whitespace inside braces means to build in, build as\n"
+ "a module or to exclude the feature respectively.\n"
+ "\n"
+ "To change any of these features, highlight it with the cursor\n"
+ "keys and press <Y> to build it in, <M> to make it a module or\n"
+ "<N> to remove it. You may also press the <Space Bar> to cycle\n"
+ "through the available options (i.e. Y->N->M->Y).\n"
+ "\n"
+ "Some additional keyboard hints:\n"
+ "\n"
+ "Menus\n"
+ "----------\n"
+ "o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n"
+ " wish to change or the submenu you wish to select and press <Enter>.\n"
+ " Submenus are designated by \"--->\", empty ones by \"----\".\n"
+ "\n"
+ " Shortcut: Press the option's highlighted letter (hotkey).\n"
+ " Pressing a hotkey more than once will sequence\n"
+ " through all visible items which use that hotkey.\n"
+ "\n"
+ " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+ " unseen options into view.\n"
+ "\n"
+ "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
+ " and press <ENTER>.\n"
+ "\n"
+ " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+ " using those letters. You may press a single <ESC>, but\n"
+ " there is a delayed response which you may find annoying.\n"
+ "\n"
+ " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+ " <Exit>, <Help>, <Save>, and <Load>.\n"
+ "\n"
+ "o To get help with an item, use the cursor keys to highlight <Help>\n"
+ " and press <ENTER>.\n"
+ "\n"
+ " Shortcut: Press <H> or <?>.\n"
+ "\n"
+ "o To toggle the display of hidden options, press <Z>.\n"
+ "\n"
+ "\n"
+ "Radiolists (Choice lists)\n"
+ "-----------\n"
+ "o Use the cursor keys to select the option you wish to set and press\n"
+ " <S> or the <SPACE BAR>.\n"
+ "\n"
+ " Shortcut: Press the first letter of the option you wish to set then\n"
+ " press <S> or <SPACE BAR>.\n"
+ "\n"
+ "o To see available help for the item, use the cursor keys to highlight\n"
+ " <Help> and Press <ENTER>.\n"
+ "\n"
+ " Shortcut: Press <H> or <?>.\n"
+ "\n"
+ " Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+ " <Help>\n"
+ "\n"
+ "\n"
+ "Data Entry\n"
+ "-----------\n"
+ "o Enter the requested information and press <ENTER>\n"
+ " If you are entering hexadecimal values, it is not necessary to\n"
+ " add the '0x' prefix to the entry.\n"
+ "\n"
+ "o For help, use the <TAB> or cursor keys to highlight the help option\n"
+ " and press <ENTER>. You can try <TAB><H> as well.\n"
+ "\n"
+ "\n"
+ "Text Box (Help Window)\n"
+ "--------\n"
+ "o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+ " keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
+ " those who are familiar with less and lynx.\n"
+ "\n"
+ "o Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
+ "\n"
+ "\n"
+ "Alternate Configuration Files\n"
+ "-----------------------------\n"
+ "Menuconfig supports the use of alternate configuration files for\n"
+ "those who, for various reasons, find it necessary to switch\n"
+ "between different configurations.\n"
+ "\n"
+ "The <Save> button will let you save the current configuration to\n"
+ "a file of your choosing. Use the <Load> button to load a previously\n"
+ "saved alternate configuration.\n"
+ "\n"
+ "Even if you don't use alternate configuration files, but you find\n"
+ "during a Menuconfig session that you have completely messed up your\n"
+ "settings, you may use the <Load> button to restore your previously\n"
+ "saved settings from \".config\" without restarting Menuconfig.\n"
+ "\n"
+ "Other information\n"
+ "-----------------\n"
+ "If you use Menuconfig in an XTERM window, make sure you have your\n"
+ "$TERM variable set to point to an xterm definition which supports\n"
+ "color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n"
+ "not display correctly in an RXVT window because rxvt displays only one\n"
+ "intensity of color, bright.\n"
+ "\n"
+ "Menuconfig will display larger menus on screens or xterms which are\n"
+ "set to display more than the standard 25 row by 80 column geometry.\n"
+ "In order for this to work, the \"stty size\" command must be able to\n"
+ "display the screen's current row and column geometry. I STRONGLY\n"
+ "RECOMMEND that you make sure you do NOT have the shell variables\n"
+ "LINES and COLUMNS exported into your environment. Some distributions\n"
+ "export those variables via /etc/profile. Some ncurses programs can\n"
+ "become confused when those variables (LINES & COLUMNS) don't reflect\n"
+ "the true screen size.\n"
+ "\n"
+ "Optional personality available\n"
+ "------------------------------\n"
+ "If you prefer to have all of the options listed in a single menu,\n"
+ "rather than the default multimenu hierarchy, run the menuconfig with\n"
+ "MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+ "\n"
+ "make MENUCONFIG_MODE=single_menu menuconfig\n"
+ "\n"
+ "<Enter> will then unroll the appropriate category, or enfold it if it\n"
+ "is already unrolled.\n"
+ "\n"
+ "Note that this mode can eventually be a little more CPU expensive\n"
+ "(especially with a larger number of unrolled categories) than the\n"
+ "default mode.\n"
+ "\n"
+
+ "Search\n"
+ "-------\n"
+ "Pressing the forward-slash (/) anywhere brings up a search dialog box.\n"
+ "\n"
+
+ "Different color themes available\n"
+ "--------------------------------\n"
+ "It is possible to select different color themes using the variable\n"
+ "MENUCONFIG_COLOR. To select a theme use:\n"
+ "\n"
+ "make MENUCONFIG_COLOR=<theme> menuconfig\n"
+ "\n"
+ "Available themes are\n"
+ " mono => selects colors suitable for monochrome displays\n"
+ " blackbg => selects a color scheme with black background\n"
+ " classic => theme with blue background. The classic look\n"
+ " bluetitle => an LCD friendly version of classic. (default)\n"
+ "\n",
+ menu_instructions[] = "Arrow keys navigate the menu. "
+ "<Enter> selects submenus ---> (or empty submenus ----). "
+ "Highlighted letters are hotkeys. "
+ "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
+ "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
+ "Legend: [*] built-in [ ] excluded <M> module < > module capable",
+ radiolist_instructions[] = "Use the arrow keys to navigate this window or "
+ "press the hotkey of the item you wish to select "
+ "followed by the <SPACE BAR>. "
+ "Press <?> for additional information about this option.",
+ inputbox_instructions_int[] =
+ "Please enter a decimal value. "
+ "Fractions will not be accepted. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+ inputbox_instructions_hex[] =
+ "Please enter a hexadecimal value. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+ inputbox_instructions_string[] =
+ "Please enter a string value. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+ setmod_text[] = "This feature depends on another which has been configured as a module.\n"
+ "As a result, this feature will be built as a module.",
+ load_config_text[] = "Enter the name of the configuration file you wish to load. "
+ "Accept the name shown to restore the configuration you "
+ "last retrieved. Leave blank to abort.",
+ load_config_help[] = "\n"
+ "For various reasons, one may wish to keep several different\n"
+ "configurations available on a single machine.\n"
+ "\n"
+ "If you have saved a previous configuration in a file other than the\n"
+ "default one, entering its name here will allow you to modify that\n"
+ "configuration.\n"
+ "\n"
+ "If you are uncertain, then you have probably never used alternate\n"
+ "configuration files. You should therefore leave this blank to abort.\n",
+ save_config_text[] = "Enter a filename to which this configuration should be saved "
+ "as an alternate. Leave blank to abort.",
+ save_config_help[] = "\n"
+ "For various reasons, one may wish to keep different configurations\n"
+ "available on a single machine.\n"
+ "\n"
+ "Entering a file name here will allow you to later retrieve, modify\n"
+ "and use the current configuration as an alternate to whatever\n"
+ "configuration options you have selected at that time.\n"
+ "\n"
+ "If you are uncertain what all this means then you should probably\n"
+ "leave this blank.\n",
+ search_help[] = "\n"
+ "Search for symbols and display their relations.\n"
+ "Regular expressions are allowed.\n"
+ "Example: search for \"^FOO\"\n"
+ "Result:\n"
+ "-----------------------------------------------------------------\n"
+ "Symbol: FOO [=m]\n"
+ "Type : tristate\n"
+ "Prompt: Foo bus is used to drive the bar HW\n"
+ " Location:\n"
+ " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+ " -> PCI support (PCI [=y])\n"
+ "(1) -> PCI access mode (<choice> [=y])\n"
+ " Defined at drivers/pci/Kconfig:47\n"
+ " Depends on: X86_LOCAL_APIC && X86_IO_APIC\n"
+ " Selects: LIBCRC32\n"
+ " Selected by: BAR [=n]\n"
+ "-----------------------------------------------------------------\n"
+ "o The line 'Type:' shows the type of the configuration option for\n"
+ " this symbol (bool, tristate, string, ...)\n"
+ "o The line 'Prompt:' shows the text used in the menu structure for\n"
+ " this symbol\n"
+ "o The 'Defined at' line tells at what file / line number the symbol\n"
+ " is defined\n"
+ "o The 'Depends on:' line tells what symbols need to be defined for\n"
+ " this symbol to be visible in the menu (selectable)\n"
+ "o The 'Location:' lines tells where in the menu structure this symbol\n"
+ " is located\n"
+ " A location followed by a [=y] indicates that this is a\n"
+ " selectable menu item - and the current value is displayed inside\n"
+ " brackets.\n"
+ " Press the key in the (#) prefix to jump directly to that\n"
+ " location. You will be returned to the current search results\n"
+ " after exiting this new menu.\n"
+ "o The 'Selects:' line tells what symbols will be automatically\n"
+ " selected if this symbol is selected (y or m)\n"
+ "o The 'Selected by' line tells what symbol has selected this symbol\n"
+ "\n"
+ "Only relevant lines are shown.\n"
+ "\n\n"
+ "Search examples:\n"
+ "Examples: USB => find all symbols containing USB\n"
+ " ^USB => find all symbols starting with USB\n"
+ " USB$ => find all symbols ending with USB\n"
+ "\n";
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+static int show_all_options;
+static int save_and_exit;
+static int silent;
+
+static void conf(struct menu *menu, struct menu *active_menu);
+
+static char filename[PATH_MAX + 1];
+static void set_config_filename(const char *config_filename)
+{
+ static char menu_backtitle[PATH_MAX + 128];
+
+ snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", config_filename, rootmenu.prompt->text);
+ set_dialog_backtitle(menu_backtitle);
+
+ snprintf(filename, sizeof(filename), "%s", config_filename);
+}
+
+struct subtitle_part
+{
+ struct list_head entries;
+ const char *text;
+};
+static LIST_HEAD(trail);
+
+static struct subtitle_list *subtitles;
+static void set_subtitle(void)
+{
+ struct subtitle_part *sp;
+ struct subtitle_list *pos, *tmp;
+
+ for (pos = subtitles; pos != NULL; pos = tmp) {
+ tmp = pos->next;
+ free(pos);
+ }
+
+ subtitles = NULL;
+ list_for_each_entry(sp, &trail, entries)
+ {
+ if (sp->text) {
+ if (pos) {
+ pos->next = xcalloc(1, sizeof(*pos));
+ pos = pos->next;
+ } else {
+ subtitles = pos = xcalloc(1, sizeof(*pos));
+ }
+ pos->text = sp->text;
+ }
+ }
+
+ set_dialog_subtitles(subtitles);
+}
+
+static void reset_subtitle(void)
+{
+ struct subtitle_list *pos, *tmp;
+
+ for (pos = subtitles; pos != NULL; pos = tmp) {
+ tmp = pos->next;
+ free(pos);
+ }
+ subtitles = NULL;
+ set_dialog_subtitles(subtitles);
+}
+
+static int show_textbox_ext(const char *title, const char *text, int r, int c, int *vscroll, int *hscroll,
+ int (*extra_key_cb)(int, size_t, size_t, void *), void *data)
+{
+ dialog_clear();
+ return dialog_textbox(title, text, r, c, vscroll, hscroll, extra_key_cb, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ show_textbox_ext(title, text, r, c, NULL, NULL, NULL, NULL);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+ show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ help.max_width = getmaxx(stdscr) - 10;
+ menu_get_ext_help(menu, &help);
+
+ show_helptext(menu_get_prompt(menu), str_get(&help));
+ str_free(&help);
+}
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ struct gstr title;
+ char *dialog_input;
+ int dres, vscroll = 0, hscroll = 0;
+ bool again;
+ struct gstr sttext;
+ struct subtitle_part stpart;
+
+ title = str_new();
+ str_printf(&title,
+ "Enter (sub)string or regexp to search for "
+ "(with or without \"%s\")",
+ CONFIG_);
+
+again:
+ dialog_clear();
+ dres = dialog_inputbox("Search Configuration Parameter", str_get(&title), 10, 75, "");
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_helptext("Search Configuration", search_help);
+ goto again;
+ default:
+ str_free(&title);
+ return;
+ }
+
+ /* strip the prefix if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+ dialog_input += strlen(CONFIG_);
+
+ sttext = str_new();
+ str_printf(&sttext, "Search (%s)", dialog_input_result);
+ stpart.text = str_get(&sttext);
+ list_add_tail(&stpart.entries, &trail);
+
+ sym_arr = sym_re_search(dialog_input);
+ do {
+ LIST_HEAD(head);
+ struct search_data data = {
+ .head = &head,
+ };
+ struct jump_key *pos, *tmp;
+
+ jump_key_char = 0;
+ res = get_relations_str(sym_arr, &head);
+ set_subtitle();
+ dres = show_textbox_ext("Search Results", str_get(&res), 0, 0, &vscroll, &hscroll, handle_search_keys, &data);
+ again = false;
+ if (dres >= '1' && dres <= '9') {
+ assert(data.target != NULL);
+ conf(data.target->parent, data.target);
+ again = true;
+ }
+ str_free(&res);
+ list_for_each_entry_safe(pos, tmp, &head, entries) free(pos);
+ } while (again);
+ free(sym_arr);
+ str_free(&title);
+ list_del(trail.prev);
+ str_free(&sttext);
+}
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+ bool visible;
+
+ /*
+ * note: menu_is_visible() has side effect that it will
+ * recalc the value of the symbol.
+ */
+ visible = menu_is_visible(menu);
+ if (show_all_options && !menu_has_prompt(menu))
+ return;
+ else if (!show_all_options && !visible)
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ switch (prop->type) {
+ case P_MENU:
+ child_count++;
+ if (single_menu_mode) {
+ item_make("%s%*c%s", menu->data ? "-->" : "++>", indent + 1, ' ', prompt);
+ } else
+ item_make(" %*c%s %s", indent + 1, ' ', prompt, menu_is_empty(menu) ? "----" : "--->");
+ item_set_tag('m');
+ item_set_data(menu);
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(" %*c*** %s ***", indent + 1, ' ', prompt);
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make("---%*c%s", indent + 1, ' ', prompt);
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_calc_choice(menu);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ item_make(" ");
+ item_set_tag(def_menu ? 't' : ':');
+ item_set_data(menu);
+
+ item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ if (def_menu)
+ item_add_str(" (%s) --->", menu_get_prompt(def_menu));
+ return;
+ } else {
+ if (menu == current_menu) {
+ item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ item_set_tag(':');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changeable(sym))
+ item_make("[%c]", val == no ? ' ' : '*');
+ else
+ item_make("-%c-", val == no ? ' ' : '*');
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ if (sym_is_changeable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make("{%c}", ch);
+ else
+ item_make("<%c>", ch);
+ } else
+ item_make("-%c-", ch);
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+ item_make("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changeable(sym)) ? "" : " (NEW)");
+ item_set_tag('s');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changeable(sym)) ? "" : " (NEW)");
+ if (menu->prompt->type == P_MENU) {
+ item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+ struct menu *child;
+ struct symbol *active;
+
+ active = sym_calc_choice(menu);
+ while (1) {
+ int res;
+ int selected;
+ item_reset();
+
+ current_menu = menu;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (child->sym)
+ item_make("%s", menu_get_prompt(child));
+ else {
+ item_make("*** %s ***", menu_get_prompt(child));
+ item_set_tag(':');
+ }
+ item_set_data(child);
+ if (child->sym == active)
+ item_set_selected(1);
+ if (child->sym == sym_calc_choice(menu))
+ item_set_tag('X');
+ }
+ dialog_clear();
+ res = dialog_checklist(prompt ? prompt : "Main Menu", radiolist_instructions, MENUBOX_HEIGHT_MIN,
+ MENUBOX_WIDTH_MIN, CHECKLIST_HEIGHT_MIN);
+ selected = item_activate_selected();
+ switch (res) {
+ case 0:
+ if (selected) {
+ child = item_data();
+ if (!child->sym)
+ break;
+
+ choice_set_value(menu, child->sym);
+ }
+ return;
+ case 1:
+ if (selected) {
+ child = item_data();
+ show_help(child);
+ active = child->sym;
+ } else
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ case -ERRDISPLAYTOOSMALL:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = inputbox_instructions_int;
+ break;
+ case S_HEX:
+ heading = inputbox_instructions_hex;
+ break;
+ case S_STRING:
+ heading = inputbox_instructions_string;
+ break;
+ default:
+ heading = "Internal mconf error!";
+ }
+ dialog_clear();
+ res = dialog_inputbox(prompt ? prompt : "Main Menu", heading, 10, 75, sym_get_string_value(menu->sym));
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym, dialog_input_result))
+ return;
+ show_textbox(NULL, "You have made an invalid entry.", 5, 43);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, load_config_text, 11, 55, filename);
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ conf_set_changed(true);
+ return;
+ }
+ show_textbox(NULL, "File does not exist!", 5, 38);
+ break;
+ case 1:
+ show_helptext("Load Alternate Configuration", load_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, save_config_text, 11, 55, filename);
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_write(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ show_textbox(NULL, "Can't create file!", 5, 60);
+ break;
+ case 1:
+ show_helptext("Save Alternate Configuration", save_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf(struct menu *menu, struct menu *active_menu)
+{
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct subtitle_part stpart;
+ struct symbol *sym;
+ int res;
+ int s_scroll = 0;
+
+ if (menu != &rootmenu)
+ stpart.text = menu_get_prompt(menu);
+ else
+ stpart.text = NULL;
+ list_add_tail(&stpart.entries, &trail);
+
+ while (1) {
+ item_reset();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+ set_subtitle();
+ dialog_clear();
+ res = dialog_menu(prompt ? prompt : "Main Menu", menu_instructions, active_menu, &s_scroll);
+ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+ break;
+ if (item_count() != 0) {
+ if (!item_activate_selected())
+ continue;
+ if (!item_tag())
+ continue;
+ }
+ submenu = item_data();
+ active_menu = item_data();
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case 0:
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+ else
+ conf(submenu, NULL);
+ break;
+ case 't':
+ if (sym_is_choice(sym))
+ conf_choice(submenu);
+ else if (submenu->prompt->type == P_MENU)
+ conf(submenu, NULL);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 2:
+ if (sym)
+ show_help(submenu);
+ else {
+ reset_subtitle();
+ show_helptext("README", mconf_readme);
+ }
+ break;
+ case 3:
+ reset_subtitle();
+ conf_save();
+ break;
+ case 4:
+ reset_subtitle();
+ conf_load();
+ break;
+ case 5:
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ show_textbox(NULL, setmod_text, 6, 74);
+ }
+ break;
+ case 6:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 7:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 8:
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu, NULL);
+ break;
+ case 9:
+ search_conf();
+ break;
+ case 10:
+ show_all_options = !show_all_options;
+ break;
+ }
+ }
+
+ list_del(trail.prev);
+}
+
+static void conf_message_callback(const char *s)
+{
+ if (save_and_exit) {
+ if (!silent)
+ printf("%s", s);
+ } else {
+ show_textbox(NULL, s, 6, 60);
+ }
+}
+
+static int handle_exit(void)
+{
+ int res;
+
+ save_and_exit = 1;
+ reset_subtitle();
+ dialog_clear();
+ if (conf_get_changed())
+ res = dialog_yesno(NULL,
+ "Do you wish to save your new configuration?\n"
+ "(Press <ESC><ESC> to continue kernel configuration.)",
+ 6, 60);
+ else
+ res = -1;
+
+ end_dialog(saved_x, saved_y);
+
+ switch (res) {
+ case 0:
+ if (conf_write(filename)) {
+ fprintf(stderr, "\n\n"
+ "Error while writing of the configuration.\n"
+ "Your configuration changes were NOT saved."
+ "\n\n");
+ return 1;
+ }
+ conf_write_autoconf(0);
+ /* fall through */
+ case -1:
+ if (!silent)
+ printf("\n\n"
+ "*** End of the configuration.\n"
+ "*** Execute 'make' to start the build or try 'make help'."
+ "\n\n");
+ res = 0;
+ break;
+ default:
+ if (!silent)
+ fprintf(stderr, "\n\n"
+ "Your configuration changes were NOT saved."
+ "\n\n");
+ if (res != KEY_ESC)
+ res = 0;
+ }
+
+ return res;
+}
+
+static void sig_handler(int signo)
+{
+ exit(handle_exit());
+}
+
+int main(int ac, char **av)
+{
+ char *mode;
+ int res;
+
+ signal(SIGINT, sig_handler);
+
+ if (ac > 1 && strcmp(av[1], "-s") == 0) {
+ silent = 1;
+ /* Silence conf_read() until the real callback is set up */
+ conf_set_message_callback(NULL);
+ av++;
+ }
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("MENUCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ if (init_dialog(NULL)) {
+ fprintf(stderr, "Your display is too small to run Menuconfig!\n");
+ fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
+ return 1;
+ }
+
+ set_config_filename(conf_get_configname());
+ conf_set_message_callback(conf_message_callback);
+ do {
+ conf(&rootmenu, NULL);
+ res = handle_exit();
+ } while (res == KEY_ESC);
+
+ return res;
+}
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
new file mode 100644
index 00000000..0f1a6513
--- /dev/null
+++ b/scripts/kconfig/menu.c
@@ -0,0 +1,864 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <list.h>
+#include <xalloc.h>
+#include "lkc.h"
+#include "internal.h"
+
+static const char nohelp_text[] = "There is no help available for this option.";
+
+struct menu rootmenu = { .type = M_MENU };
+static struct menu **last_entry_ptr;
+
+/**
+ * menu_next - return the next menu entry with depth-first traversal
+ * @menu: pointer to the current menu
+ * @root: root of the sub-tree to traverse. If NULL is given, the traveral
+ * continues until it reaches the end of the entire menu tree.
+ * return: the menu to visit next, or NULL when it reaches the end.
+ */
+struct menu *menu_next(struct menu *menu, struct menu *root)
+{
+ if (menu->list)
+ return menu->list;
+
+ while (menu != root && !menu->next)
+ menu = menu->parent;
+
+ if (menu == root)
+ return NULL;
+
+ return menu->next;
+}
+
+void menu_warn(const struct menu *menu, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_warn(const struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+void _menu_init(void)
+{
+ current_entry = current_menu = &rootmenu;
+ last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym, enum menu_type type)
+{
+ struct menu *menu;
+
+ menu = xmalloc(sizeof(*menu));
+ memset(menu, 0, sizeof(*menu));
+ menu->type = type;
+ menu->sym = sym;
+ menu->parent = current_menu;
+ menu->filename = cur_filename;
+ menu->lineno = cur_lineno;
+
+ *last_entry_ptr = menu;
+ last_entry_ptr = &menu->next;
+ current_entry = menu;
+ if (sym)
+ list_add_tail(&menu->link, &sym->menus);
+}
+
+struct menu *menu_add_menu(void)
+{
+ last_entry_ptr = &current_entry->list;
+ current_menu = current_entry;
+ return current_menu;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = &current_menu->next;
+ current_menu = current_menu->parent;
+}
+
+/*
+ * 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 = expr_alloc_one(E_NOT, rewrite_m(e->left.expr));
+ break;
+ case E_OR:
+ case E_AND:
+ e = expr_alloc_two(e->type,
+ rewrite_m(e->left.expr),
+ rewrite_m(e->right.expr));
+ break;
+ case E_SYMBOL:
+ /* change 'm' into 'm' && MODULES */
+ if (e->left.sym == &symbol_mod)
+ return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+ current_entry->dep = expr_alloc_and(current_entry->dep, dep);
+}
+
+void menu_set_type(int type)
+{
+ struct symbol *sym = current_entry->sym;
+
+ if (sym->type == type)
+ return;
+ if (sym->type == S_UNKNOWN) {
+ sym->type = type;
+ return;
+ }
+ menu_warn(current_entry,
+ "ignoring type redefinition of '%s' from '%s' to '%s'",
+ sym->name ? sym->name : "<choice>",
+ sym_type_name(sym->type), sym_type_name(type));
+}
+
+static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
+ struct expr *dep)
+{
+ struct property *prop;
+
+ prop = xmalloc(sizeof(*prop));
+ memset(prop, 0, sizeof(*prop));
+ prop->type = type;
+ prop->filename = cur_filename;
+ prop->lineno = cur_lineno;
+ prop->menu = current_entry;
+ prop->expr = expr;
+ prop->visible.expr = dep;
+
+ /* append property to the prop list of symbol */
+ if (current_entry->sym) {
+ struct property **propp;
+
+ for (propp = &current_entry->sym->prop;
+ *propp;
+ propp = &(*propp)->next)
+ ;
+ *propp = prop;
+ }
+
+ return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, const char *prompt,
+ struct expr *dep)
+{
+ struct property *prop = menu_add_prop(type, NULL, dep);
+
+ if (isspace(*prompt)) {
+ prop_warn(prop, "leading whitespace ignored");
+ while (isspace(*prompt))
+ prompt++;
+ }
+ if (current_entry->prompt)
+ prop_warn(prop, "prompt redefined");
+
+ /* Apply all upper menus' visibilities to actual prompts. */
+ if (type == P_PROMPT) {
+ struct menu *menu = current_entry;
+
+ while ((menu = menu->parent) != NULL) {
+
+ if (!menu->visibility)
+ continue;
+ prop->visible.expr = expr_alloc_and(prop->visible.expr,
+ menu->visibility);
+ }
+ }
+
+ current_entry->prompt = prop;
+ prop->text = prompt;
+
+ return prop;
+}
+
+void menu_add_visibility(struct expr *expr)
+{
+ current_entry->visibility = expr_alloc_and(current_entry->visibility,
+ expr);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+ menu_add_prop(type, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, expr_alloc_symbol(sym), dep);
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
+{
+ return sym2->type == S_INT || sym2->type == S_HEX ||
+ (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+static void sym_check_prop(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *sym2;
+ char *use;
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_DEFAULT:
+ if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+ prop->expr->type != E_SYMBOL)
+ prop_warn(prop,
+ "default for config symbol '%s'"
+ " must be a single symbol", sym->name);
+ if (prop->expr->type != E_SYMBOL)
+ break;
+ sym2 = prop_get_symbol(prop);
+ if (sym->type == S_HEX || sym->type == S_INT) {
+ if (!menu_validate_number(sym, sym2))
+ prop_warn(prop,
+ "'%s': number is invalid",
+ sym->name);
+ }
+ if (sym_is_choice(sym)) {
+ struct menu *choice = sym_get_choice_menu(sym2);
+
+ if (!choice || choice->sym != sym)
+ prop_warn(prop,
+ "choice default symbol '%s' is not contained in the choice",
+ sym2->name);
+ }
+ break;
+ case P_SELECT:
+ case P_IMPLY:
+ use = prop->type == P_SELECT ? "select" : "imply";
+ sym2 = prop_get_symbol(prop);
+ if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+ prop_warn(prop,
+ "config symbol '%s' uses %s, but is "
+ "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 bool and "
+ "tristate type", sym2->name, use);
+ break;
+ case P_RANGE:
+ if (sym->type != S_INT && sym->type != S_HEX)
+ prop_warn(prop, "range is only allowed "
+ "for int or hex symbols");
+ if (!menu_validate_number(sym, prop->expr->left.sym) ||
+ !menu_validate_number(sym, prop->expr->right.sym))
+ prop_warn(prop, "range is invalid");
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+static void _menu_finalize(struct menu *parent, bool inside_choice)
+{
+ struct menu *menu, *last_menu;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *basedep, *dep, *dep2;
+
+ sym = parent->sym;
+ if (parent->list) {
+ /*
+ * This menu node has children. We (recursively) process them
+ * and propagate parent dependencies before moving on.
+ */
+
+ /* For each child menu node... */
+ for (menu = parent->list; menu; menu = menu->next) {
+ /*
+ * 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(parent->dep, 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;
+
+ /*
+ * 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(basedep, dep);
+ dep = expr_eliminate_dups(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,
+ expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
+ } else if (prop->type == P_IMPLY) {
+ struct symbol *es = prop_get_symbol(prop);
+ es->implied.expr = expr_alloc_or(es->implied.expr,
+ expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
+ }
+ }
+ }
+
+ /*
+ * Recursively process children in the same fashion before
+ * moving on
+ */
+ for (menu = parent->list; menu; menu = menu->next)
+ _menu_finalize(menu, sym && sym_is_choice(sym));
+ } else if (!inside_choice && 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 = basedep;
+ expr_eliminate_eq(&dep, &dep2);
+ if (!expr_is_yes(dep2)) {
+ /* Not superset, quit */
+ break;
+ }
+ /* Superset, put in submenu */
+ next:
+ _menu_finalize(menu, false);
+ menu->parent = parent;
+ last_menu = menu;
+ }
+ if (last_menu) {
+ parent->list = parent->next;
+ parent->next = last_menu->next;
+ last_menu->next = NULL;
+ }
+
+ sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
+ }
+ for (menu = parent->list; menu; menu = menu->next) {
+ /*
+ * 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;
+ if (!last_menu->next)
+ break;
+ }
+ last_menu->next = menu->next;
+ menu->next = menu->list;
+ menu->list = NULL;
+ }
+ }
+
+ if (sym && !(sym->flags & SYMBOL_WARNED)) {
+ if (sym->type == S_UNKNOWN)
+ menu_warn(parent, "config symbol defined without type");
+
+ /* Check properties connected to this symbol */
+ sym_check_prop(sym);
+ sym->flags |= SYMBOL_WARNED;
+ }
+}
+
+void menu_finalize(void)
+{
+ _menu_finalize(&rootmenu, false);
+}
+
+bool menu_has_prompt(const struct menu *menu)
+{
+ if (!menu->prompt)
+ return false;
+ return true;
+}
+
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+ struct menu *child;
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child))
+ return(false);
+ }
+ return(true);
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+ struct menu *child;
+ struct symbol *sym;
+ tristate visible;
+
+ if (!menu->prompt)
+ return false;
+
+ if (menu->visibility) {
+ if (expr_calc_value(menu->visibility) == no)
+ return false;
+ }
+
+ sym = menu->sym;
+ if (sym) {
+ sym_calc_value(sym);
+ visible = menu->prompt->visible.tri;
+ } else
+ visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+ if (visible != no)
+ return true;
+
+ if (!sym || sym_get_tristate_value(menu->sym) == no)
+ return false;
+
+ for (child = menu->list; child; child = child->next)
+ if (menu_is_visible(child))
+ return true;
+
+ return false;
+}
+
+const char *menu_get_prompt(const struct menu *menu)
+{
+ if (menu->prompt)
+ return menu->prompt->text;
+ else if (menu->sym)
+ return menu->sym->name;
+ return NULL;
+}
+
+/**
+ * menu_get_parent_menu - return the parent menu or NULL
+ * @menu: pointer to the menu
+ * return: the parent menu, or NULL if there is no parent.
+ */
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+ for (menu = menu->parent; menu; menu = menu->parent)
+ if (menu->type == M_MENU)
+ return menu;
+
+ return NULL;
+}
+
+/**
+ * menu_get_menu_or_parent_menu - return the parent menu or the menu itself
+ * @menu: pointer to the menu
+ * return: the parent menu. If the given argument is already a menu, return
+ * itself.
+ */
+struct menu *menu_get_menu_or_parent_menu(struct menu *menu)
+{
+ enum prop_type type;
+
+ for (; menu != &rootmenu; menu = menu->parent) {
+ type = menu->prompt ? menu->prompt->type : 0;
+ if (type == P_MENU)
+ break;
+ }
+ return menu;
+}
+
+static void get_def_str(struct gstr *r, const struct menu *menu)
+{
+ str_printf(r, "Defined at %s:%d\n",
+ menu->filename, menu->lineno);
+}
+
+static void get_dep_str(struct gstr *r, const struct expr *expr,
+ const char *prefix)
+{
+ if (!expr_is_yes(expr)) {
+ str_append(r, prefix);
+ expr_gstr_print(expr, r);
+ str_append(r, "\n");
+ }
+}
+
+int __attribute__((weak)) get_jump_key_char(void)
+{
+ return -1;
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop,
+ struct list_head *head)
+{
+ int i, j;
+ struct menu *submenu[8], *menu, *location = NULL;
+ struct jump_key *jump = NULL;
+
+ str_printf(r, " Prompt: %s\n", prop->text);
+
+ get_dep_str(r, prop->menu->dep, " Depends on: ");
+ /*
+ * Most prompts in Linux have visibility that exactly matches their
+ * dependencies. For these, we print only the dependencies to improve
+ * readability. However, prompts with inline "if" expressions and
+ * prompts with a parent that has a "visible if" expression have
+ * differing dependencies and visibility. In these rare cases, we
+ * print both.
+ */
+ if (!expr_eq(prop->menu->dep, prop->visible.expr))
+ get_dep_str(r, prop->visible.expr, " Visible if: ");
+
+ menu = prop->menu;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+ submenu[i++] = menu;
+ if (location == NULL && menu_is_visible(menu))
+ location = menu;
+ }
+ if (head && location) {
+ jump = xmalloc(sizeof(struct jump_key));
+ jump->target = location;
+ list_add_tail(&jump->entries, head);
+ }
+
+ str_printf(r, " Location:\n");
+ for (j = 0; --i >= 0; j++) {
+ int jk = -1;
+ int indent = 2 * j + 4;
+
+ menu = submenu[i];
+ if (jump && menu == location) {
+ jump->offset = strlen(r->s);
+ jk = get_jump_key_char();
+ }
+
+ if (jk >= 0) {
+ str_printf(r, "(%c)", jk);
+ indent -= 3;
+ }
+
+ str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : "<choice>",
+ sym_get_string_value(menu->sym));
+ }
+ str_append(r, "\n");
+ }
+}
+
+static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
+ enum prop_type tok, const char *prefix)
+{
+ bool hit = false;
+ struct property *prop;
+
+ for_all_properties(sym, prop, tok) {
+ if (!hit) {
+ str_append(r, prefix);
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+}
+
+/*
+ * head is optional and may be NULL
+ */
+static void get_symbol_str(struct gstr *r, struct symbol *sym,
+ struct list_head *head)
+{
+ struct property *prop;
+ struct menu *menu;
+
+ if (sym && sym->name) {
+ str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+ sym_get_string_value(sym));
+ str_printf(r, "Type : %s\n", sym_type_name(sym->type));
+ if (sym->type == S_INT || sym->type == S_HEX) {
+ prop = sym_get_range_prop(sym);
+ if (prop) {
+ str_printf(r, "Range : ");
+ expr_gstr_print(prop->expr, r);
+ str_append(r, "\n");
+ }
+ }
+ }
+
+ /* Print the definitions with prompts before the ones without */
+ list_for_each_entry(menu, &sym->menus, link) {
+ if (menu->prompt) {
+ get_def_str(r, menu);
+ get_prompt_str(r, menu->prompt, head);
+ }
+ }
+
+ list_for_each_entry(menu, &sym->menus, link) {
+ if (!menu->prompt) {
+ get_def_str(r, menu);
+ get_dep_str(r, menu->dep, " Depends on: ");
+ }
+ }
+
+ get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
+ if (sym->rev_dep.expr) {
+ 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: ");
+ if (sym->implied.expr) {
+ 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");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
+{
+ struct symbol *sym;
+ struct gstr res = str_new();
+ int i;
+
+ 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");
+ return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+ struct symbol *sym = menu->sym;
+ const char *help_text = nohelp_text;
+
+ if (menu->help) {
+ if (sym->name)
+ str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+ help_text = menu->help;
+ }
+ str_printf(help, "%s\n", help_text);
+ if (sym)
+ get_symbol_str(help, sym, NULL);
+}
+
+/**
+ * menu_dump - dump all menu entries in a tree-like format
+ */
+void menu_dump(void)
+{
+ struct menu *menu = &rootmenu;
+ unsigned long long bits = 0;
+ int indent = 0;
+
+ while (menu) {
+
+ for (int i = indent - 1; i >= 0; i--) {
+ if (bits & (1ULL << i)) {
+ if (i > 0)
+ printf("| ");
+ else
+ printf("|-- ");
+ } else {
+ if (i > 0)
+ printf(" ");
+ else
+ printf("`-- ");
+ }
+ }
+
+ switch (menu->type) {
+ case M_CHOICE:
+ printf("choice \"%s\"\n", menu->prompt->text);
+ break;
+ case M_COMMENT:
+ printf("comment \"%s\"\n", menu->prompt->text);
+ break;
+ case M_IF:
+ printf("if\n");
+ break;
+ case M_MENU:
+ printf("menu \"%s\"", menu->prompt->text);
+ if (!menu->sym) {
+ printf("\n");
+ break;
+ }
+ printf(" + ");
+ /* fallthrough */
+ case M_NORMAL:
+ printf("symbol %s\n", menu->sym->name);
+ break;
+ }
+ if (menu->list) {
+ bits <<= 1;
+ menu = menu->list;
+ if (menu->next)
+ bits |= 1;
+ else
+ bits &= ~1;
+ indent++;
+ continue;
+ }
+
+ while (menu && !menu->next) {
+ menu = menu->parent;
+ bits >>= 1;
+ indent--;
+ }
+
+ if (menu) {
+ menu = menu->next;
+ if (menu->next)
+ bits |= 1;
+ else
+ bits &= ~1;
+ }
+ }
+}
diff --git a/scripts/kconfig/menubox.c b/scripts/kconfig/menubox.c
new file mode 100644
index 00000000..d4c19b7b
--- /dev/null
+++ b/scripts/kconfig/menubox.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * menubox.c -- implements the menu box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ */
+
+/*
+ * Changes by Clifford Wolf (god@clifford.at)
+ *
+ * [ 1998-06-13 ]
+ *
+ * *) A bugfix for the Page-Down problem
+ *
+ * *) Formerly when I used Page Down and Page Up, the cursor would be set
+ * to the first position in the menu box. Now lxdialog is a bit
+ * smarter and works more like other menu systems (just have a look at
+ * it).
+ *
+ * *) Formerly if I selected something my scrolling would be broken because
+ * lxdialog is re-invoked by the Menuconfig shell script, can't
+ * remember the last scrolling position, and just sets it so that the
+ * cursor is at the bottom of the box. Now it writes the temporary file
+ * lxdialog.scrltmp which contains this information. The file is
+ * deleted by lxdialog if the user leaves a submenu or enters a new
+ * one, but it would be nice if Menuconfig could make another "rm -f"
+ * just to be sure. Just try it out - you will recognise a difference!
+ *
+ * [ 1998-06-14 ]
+ *
+ * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ * and menus change their size on the fly.
+ *
+ * *) If for some reason the last scrolling position is not saved by
+ * lxdialog, it sets the scrolling so that the selected item is in the
+ * middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+ int selected, int hotkey)
+{
+ int j;
+ char *menu_item = malloc(menu_width + 1);
+
+ strncpy(menu_item, item, menu_width - item_x);
+ menu_item[menu_width - item_x] = '\0';
+ j = first_alpha(menu_item, "YyNnMmHh");
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, line_y, 0);
+ wclrtoeol(win);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ mvwaddstr(win, line_y, item_x, menu_item);
+ if (hotkey) {
+ wattrset(win, selected ? dlg.tag_key_selected.atr
+ : dlg.tag_key.atr);
+ mvwaddch(win, line_y, item_x + j, menu_item[j]);
+ }
+ if (selected) {
+ wmove(win, line_y, item_x + 1);
+ }
+ free(menu_item);
+ wrefresh(win);
+}
+
+#define print_item(index, choice, selected) \
+do { \
+ item_set(index); \
+ do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+ int height)
+{
+ int cur_y, cur_x;
+
+ getyx(win, cur_y, cur_x);
+
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+ wrefresh(win);
+
+ if ((height < item_no) && (scroll + height < item_no)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ wmove(win, cur_y, cur_x);
+ wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+ int x = width / 2 - 28;
+ int y = height - 2;
+
+ print_button(win, "Select", y, x, selected == 0);
+ print_button(win, " Exit ", y, x + 12, selected == 1);
+ print_button(win, " Help ", y, x + 24, selected == 2);
+ print_button(win, " Save ", y, x + 36, selected == 3);
+ print_button(win, " Load ", y, x + 48, selected == 4);
+
+ wmove(win, y, x + 1 + 12 * selected);
+ wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+ /* Scroll menu up */
+ scrollok(win, TRUE);
+ wscrl(win, n);
+ scrollok(win, FALSE);
+ *scroll = *scroll + n;
+ wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll)
+{
+ int i, j, x, y, box_x, box_y;
+ int height, width, menu_height;
+ int key = 0, button = 0, scroll = 0, choice = 0;
+ int first_item = 0, max_choice;
+ WINDOW *dialog, *menu;
+
+do_resize:
+ height = getmaxy(stdscr);
+ width = getmaxx(stdscr);
+ if (height < MENUBOX_HEIGHT_MIN || width < MENUBOX_WIDTH_MIN)
+ return -ERRDISPLAYTOOSMALL;
+
+ height -= 4;
+ width -= 5;
+ menu_height = height - 10;
+
+ max_choice = MIN(menu_height, item_count());
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ menu_width = width - 6;
+ box_y = height - menu_height - 5;
+ box_x = (width - menu_width) / 2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width,
+ y + box_y + 1, x + box_x + 1);
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ if (menu_width >= 80)
+ item_x = (menu_width - 70) / 2;
+ else
+ item_x = 4;
+
+ /* Set choice to default item */
+ item_foreach()
+ if (selected && (selected == item_data()))
+ choice = item_n();
+ /* get the saved scroll info */
+ scroll = *s_scroll;
+ if ((scroll <= choice) && (scroll + max_choice > choice) &&
+ (scroll >= 0) && (scroll + max_choice <= item_count())) {
+ first_item = scroll;
+ choice = choice - scroll;
+ } else {
+ scroll = 0;
+ }
+ if ((choice >= max_choice)) {
+ if (choice >= item_count() - max_choice / 2)
+ scroll = first_item = item_count() - max_choice;
+ else
+ scroll = first_item = choice - max_choice / 2;
+ choice = choice - scroll;
+ }
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++) {
+ print_item(first_item + i, i, i == choice);
+ }
+
+ wnoutrefresh(menu);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ print_buttons(dialog, height, width, 0);
+ wmove(menu, choice, item_x + 1);
+ wrefresh(menu);
+
+ while (key != KEY_ESC) {
+ key = wgetch(menu);
+
+ if (key < 256 && isalpha(key))
+ key = tolower(key);
+
+ if (strchr("ynmh ", key))
+ i = max_choice;
+ else {
+ for (i = choice + 1; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ if (i == max_choice)
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ }
+
+ if (item_count() != 0 &&
+ (i < max_choice ||
+ key == KEY_UP || key == KEY_DOWN ||
+ key == '-' || key == '+' ||
+ key == KEY_PPAGE || key == KEY_NPAGE)) {
+ /* Remove highligt of current item */
+ print_item(scroll + choice, choice, FALSE);
+
+ if (key == KEY_UP || key == '-') {
+ if (choice < 2 && scroll) {
+ /* Scroll menu down */
+ do_scroll(menu, &scroll, -1);
+
+ print_item(scroll, 0, FALSE);
+ } else
+ choice = MAX(choice - 1, 0);
+
+ } else if (key == KEY_DOWN || key == '+') {
+ print_item(scroll+choice, choice, FALSE);
+
+ if ((choice > max_choice - 3) &&
+ (scroll + max_choice < item_count())) {
+ /* Scroll menu up */
+ do_scroll(menu, &scroll, 1);
+
+ print_item(scroll+max_choice - 1,
+ max_choice - 1, FALSE);
+ } else
+ choice = MIN(choice + 1, max_choice - 1);
+
+ } else if (key == KEY_PPAGE) {
+ scrollok(menu, TRUE);
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll > 0) {
+ do_scroll(menu, &scroll, -1);
+ print_item(scroll, 0, FALSE);
+ } else {
+ if (choice > 0)
+ choice--;
+ }
+ }
+
+ } else if (key == KEY_NPAGE) {
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll + max_choice < item_count()) {
+ do_scroll(menu, &scroll, 1);
+ print_item(scroll+max_choice-1,
+ max_choice - 1, FALSE);
+ } else {
+ if (choice + 1 < max_choice)
+ choice++;
+ }
+ }
+ } else
+ choice = i;
+
+ print_item(scroll + choice, choice, TRUE);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(menu);
+
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_LEFT:
+ case TAB:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 4 : (button > 4 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(menu);
+ break;
+ case ' ':
+ case 's':
+ case 'y':
+ case 'n':
+ case 'm':
+ case '/':
+ case 'h':
+ case '?':
+ case 'z':
+ case '\n':
+ /* save scroll info */
+ *s_scroll = scroll;
+ delwin(menu);
+ delwin(dialog);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ switch (key) {
+ case 'h':
+ case '?':
+ return 2;
+ case 's':
+ case 'y':
+ return 5;
+ case 'n':
+ return 6;
+ case 'm':
+ return 7;
+ case ' ':
+ return 8;
+ case '/':
+ return 9;
+ case 'z':
+ return 10;
+ case '\n':
+ return button;
+ }
+ return 0;
+ case 'e':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(menu);
+ break;
+ case KEY_RESIZE:
+ on_key_resize();
+ delwin(menu);
+ delwin(dialog);
+ goto do_resize;
+ }
+ }
+ delwin(menu);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
new file mode 100755
index 00000000..79c09b37
--- /dev/null
+++ b/scripts/kconfig/merge_config.sh
@@ -0,0 +1,213 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# merge_config.sh - Takes a list of config fragment values, and merges
+# them one by one. Provides warnings on overridden values, and specified
+# values that did not make it to the resulting .config file (due to missed
+# dependencies or config symbol removal).
+#
+# Portions reused from kconf_check and generate_cfg:
+# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
+# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
+#
+# Copyright (c) 2009-2010 Wind River Systems, Inc.
+# Copyright 2011 Linaro
+
+set -e
+
+clean_up() {
+ rm -f $TMP_FILE
+ rm -f $MERGE_FILE
+}
+
+usage() {
+ echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
+ echo " -h display this help text"
+ echo " -m only merge the fragments, do not execute the make command"
+ echo " -n use allnoconfig instead of alldefconfig"
+ echo " -r list redundant entries when merging fragments"
+ echo " -y make builtin have precedence over modules"
+ echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
+ echo " -s strict mode. Fail if the fragment redefines any value."
+ echo " -Q disable warning messages for overridden options."
+ echo
+ echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
+}
+
+RUNMAKE=true
+ALLTARGET=alldefconfig
+WARNREDUN=false
+BUILTIN=false
+OUTPUT=.
+STRICT=false
+CONFIG_PREFIX=${CONFIG_-CONFIG_}
+WARNOVERRIDE=echo
+
+while true; do
+ case $1 in
+ "-n")
+ ALLTARGET=allnoconfig
+ shift
+ continue
+ ;;
+ "-m")
+ RUNMAKE=false
+ shift
+ continue
+ ;;
+ "-h")
+ usage
+ exit
+ ;;
+ "-r")
+ WARNREDUN=true
+ shift
+ continue
+ ;;
+ "-y")
+ BUILTIN=true
+ shift
+ continue
+ ;;
+ "-O")
+ if [ -d $2 ];then
+ OUTPUT=$(echo $2 | sed 's/\/*$//')
+ else
+ echo "output directory $2 does not exist" 1>&2
+ exit 1
+ fi
+ shift 2
+ continue
+ ;;
+ "-s")
+ STRICT=true
+ shift
+ continue
+ ;;
+ "-Q")
+ WARNOVERRIDE=true
+ shift
+ continue
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+if [ "$#" -lt 1 ] ; then
+ usage
+ exit
+fi
+
+if [ -z "$KCONFIG_CONFIG" ]; then
+ if [ "$OUTPUT" != . ]; then
+ KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config")
+ else
+ KCONFIG_CONFIG=.config
+ fi
+fi
+
+INITFILE=$1
+shift;
+
+if [ ! -r "$INITFILE" ]; then
+ echo "The base file '$INITFILE' does not exist. Creating one..." >&2
+ touch "$INITFILE"
+fi
+
+MERGE_LIST=$*
+SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
+SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
+
+TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
+MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
+
+echo "Using $INITFILE as base"
+
+trap clean_up EXIT
+
+cat $INITFILE > $TMP_FILE
+
+# Merge files, printing warnings on overridden values
+for ORIG_MERGE_FILE in $MERGE_LIST ; do
+ echo "Merging $ORIG_MERGE_FILE"
+ if [ ! -r "$ORIG_MERGE_FILE" ]; then
+ echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
+ exit 1
+ fi
+ cat $ORIG_MERGE_FILE > $MERGE_FILE
+ CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
+
+ for CFG in $CFG_LIST ; do
+ grep -q -w $CFG $TMP_FILE || continue
+ PREV_VAL=$(grep -w $CFG $TMP_FILE)
+ NEW_VAL=$(grep -w $CFG $MERGE_FILE)
+ BUILTIN_FLAG=false
+ if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
+ ${WARNOVERRIDE} Previous value: $PREV_VAL
+ ${WARNOVERRIDE} New value: $NEW_VAL
+ ${WARNOVERRIDE} -y passed, will not demote y to m
+ ${WARNOVERRIDE}
+ BUILTIN_FLAG=true
+ elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
+ ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
+ ${WARNOVERRIDE} Previous value: $PREV_VAL
+ ${WARNOVERRIDE} New value: $NEW_VAL
+ ${WARNOVERRIDE}
+ if [ "$STRICT" = "true" ]; then
+ STRICT_MODE_VIOLATED=true
+ fi
+ elif [ "$WARNREDUN" = "true" ]; then
+ ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
+ fi
+ if [ "$BUILTIN_FLAG" = "false" ]; then
+ sed -i "/$CFG[ =]/d" $TMP_FILE
+ else
+ sed -i "/$CFG[ =]/d" $MERGE_FILE
+ fi
+ done
+ # In case the previous file lacks a new line at the end
+ echo >> $TMP_FILE
+ cat $MERGE_FILE >> $TMP_FILE
+done
+
+if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
+ echo "The fragment redefined a value and strict mode had been passed."
+ exit 1
+fi
+
+if [ "$RUNMAKE" = "false" ]; then
+ cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
+ echo "#"
+ echo "# merged configuration written to $KCONFIG_CONFIG (needs make)"
+ echo "#"
+ exit
+fi
+
+# If we have an output dir, setup the O= argument, otherwise leave
+# it blank, since O=. will create an unnecessary ./source softlink
+OUTPUT_ARG=""
+if [ "$OUTPUT" != "." ] ; then
+ OUTPUT_ARG="O=$OUTPUT"
+fi
+
+
+# Use the merged file as the starting point for:
+# alldefconfig: Fills in any missing symbols with Kconfig default
+# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
+make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
+
+
+# Check all specified config values took (might have missed-dependency issues)
+for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do
+
+ REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
+ ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true)
+ if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
+ echo "Value requested for $CFG not in final .config"
+ echo "Requested value: $REQUESTED_VAL"
+ echo "Actual value: $ACTUAL_VAL"
+ echo ""
+ fi
+done
diff --git a/scripts/kconfig/mnconf-common.c b/scripts/kconfig/mnconf-common.c
new file mode 100644
index 00000000..8e24b071
--- /dev/null
+++ b/scripts/kconfig/mnconf-common.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <list.h>
+#include "expr.h"
+#include "mnconf-common.h"
+
+int jump_key_char;
+
+int next_jump_key(int key)
+{
+ if (key < '1' || key > '9')
+ return '1';
+
+ key++;
+
+ if (key > '9')
+ key = '1';
+
+ return key;
+}
+
+int handle_search_keys(int key, size_t start, size_t end, void *_data)
+{
+ struct search_data *data = _data;
+ struct jump_key *pos;
+ int index = 0;
+
+ if (key < '1' || key > '9')
+ return 0;
+
+ list_for_each_entry(pos, data->head, entries) {
+ index = next_jump_key(index);
+
+ if (pos->offset < start)
+ continue;
+
+ if (pos->offset >= end)
+ break;
+
+ if (key == index) {
+ data->target = pos->target;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int get_jump_key_char(void)
+{
+ jump_key_char = next_jump_key(jump_key_char);
+
+ return jump_key_char;
+}
diff --git a/scripts/kconfig/mnconf-common.h b/scripts/kconfig/mnconf-common.h
new file mode 100644
index 00000000..53bd7292
--- /dev/null
+++ b/scripts/kconfig/mnconf-common.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef MNCONF_COMMON_H
+#define MNCONF_COMMON_H
+
+#include <stddef.h>
+
+#include <list_types.h>
+
+struct search_data {
+ struct list_head *head;
+ struct menu *target;
+};
+
+extern int jump_key_char;
+
+int next_jump_key(int key);
+int handle_search_keys(int key, size_t start, size_t end, void *_data);
+int get_jump_key_char(void);
+
+#endif /* MNCONF_COMMON_H */
diff --git a/scripts/kconfig/parser.tab.c b/scripts/kconfig/parser.tab.c
new file mode 100644
index 00000000..c306b2fc
--- /dev/null
+++ b/scripts/kconfig/parser.tab.c
@@ -0,0 +1,2645 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_HELPTEXT = 258,
+ T_WORD = 259,
+ T_WORD_QUOTE = 260,
+ T_BOOL = 261,
+ T_CHOICE = 262,
+ T_CLOSE_PAREN = 263,
+ T_COLON_EQUAL = 264,
+ T_COMMENT = 265,
+ T_CONFIG = 266,
+ T_DEFAULT = 267,
+ T_DEF_BOOL = 268,
+ T_DEF_TRISTATE = 269,
+ T_DEPENDS = 270,
+ T_ENDCHOICE = 271,
+ T_ENDIF = 272,
+ T_ENDMENU = 273,
+ T_HELP = 274,
+ T_HEX = 275,
+ T_IF = 276,
+ T_IMPLY = 277,
+ T_INT = 278,
+ T_MAINMENU = 279,
+ T_MENU = 280,
+ T_MENUCONFIG = 281,
+ T_MODULES = 282,
+ T_ON = 283,
+ T_OPEN_PAREN = 284,
+ T_PLUS_EQUAL = 285,
+ T_PROMPT = 286,
+ T_RANGE = 287,
+ T_SELECT = 288,
+ T_SOURCE = 289,
+ T_STRING = 290,
+ T_TRANSITIONAL = 291,
+ T_TRISTATE = 292,
+ T_VISIBLE = 293,
+ T_EOL = 294,
+ T_ASSIGN_VAL = 295,
+ T_OR = 296,
+ T_AND = 297,
+ T_UNEQUAL = 298,
+ T_EQUAL = 299,
+ T_GREATER_EQUAL = 300,
+ T_GREATER = 301,
+ T_LESS_EQUAL = 302,
+ T_LESS = 303,
+ T_NOT = 304
+ };
+#endif
+/* Tokens. */
+#define T_HELPTEXT 258
+#define T_WORD 259
+#define T_WORD_QUOTE 260
+#define T_BOOL 261
+#define T_CHOICE 262
+#define T_CLOSE_PAREN 263
+#define T_COLON_EQUAL 264
+#define T_COMMENT 265
+#define T_CONFIG 266
+#define T_DEFAULT 267
+#define T_DEF_BOOL 268
+#define T_DEF_TRISTATE 269
+#define T_DEPENDS 270
+#define T_ENDCHOICE 271
+#define T_ENDIF 272
+#define T_ENDMENU 273
+#define T_HELP 274
+#define T_HEX 275
+#define T_IF 276
+#define T_IMPLY 277
+#define T_INT 278
+#define T_MAINMENU 279
+#define T_MENU 280
+#define T_MENUCONFIG 281
+#define T_MODULES 282
+#define T_ON 283
+#define T_OPEN_PAREN 284
+#define T_PLUS_EQUAL 285
+#define T_PROMPT 286
+#define T_RANGE 287
+#define T_SELECT 288
+#define T_SOURCE 289
+#define T_STRING 290
+#define T_TRANSITIONAL 291
+#define T_TRISTATE 292
+#define T_VISIBLE 293
+#define T_EOL 294
+#define T_ASSIGN_VAL 295
+#define T_OR 296
+#define T_AND 297
+#define T_UNEQUAL 298
+#define T_EQUAL 299
+#define T_GREATER_EQUAL 300
+#define T_GREATER 301
+#define T_LESS_EQUAL 302
+#define T_LESS 303
+#define T_NOT 304
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 5 "parser.y"
+
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <xalloc.h>
+#include "lkc.h"
+#include "internal.h"
+#include "preprocess.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+static void yyerror(const char *err);
+static void zconf_error(const char *err, ...);
+static bool zconf_endtoken(const char *tokenname,
+ const char *expected_tokenname);
+
+struct menu *current_menu, *current_entry, *current_choice;
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 36 "parser.y"
+{
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ enum symbol_type type;
+ enum variable_flavor flavor;
+}
+/* Line 193 of yacc.c. */
+#line 233 "parser.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 246 "parser.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 6
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 181
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 50
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 45
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 101
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 178
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 304
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 12, 13, 16, 19, 22,
+ 25, 28, 31, 34, 37, 42, 46, 47, 50, 53,
+ 56, 60, 64, 67, 71, 74, 75, 78, 81, 84,
+ 88, 93, 96, 101, 106, 111, 117, 120, 123, 126,
+ 128, 132, 133, 136, 139, 142, 147, 152, 154, 156,
+ 158, 160, 162, 164, 166, 168, 172, 174, 178, 182,
+ 186, 189, 191, 195, 196, 199, 202, 206, 210, 213,
+ 214, 217, 220, 223, 228, 232, 233, 236, 239, 242,
+ 245, 246, 249, 251, 255, 259, 263, 267, 271, 275,
+ 279, 282, 286, 290, 292, 294, 296, 301, 303, 305,
+ 307, 308
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 51, 0, -1, 52, 53, -1, 53, -1, 24, 5,
+ 39, -1, -1, 53, 92, -1, 53, 64, -1, 53,
+ 80, -1, 53, 56, -1, 53, 71, -1, 53, 76,
+ -1, 53, 58, -1, 53, 78, -1, 53, 4, 1,
+ 39, -1, 53, 1, 39, -1, -1, 54, 80, -1,
+ 54, 56, -1, 54, 72, -1, 54, 1, 39, -1,
+ 11, 90, 39, -1, 55, 59, -1, 26, 90, 39,
+ -1, 57, 59, -1, -1, 59, 60, -1, 59, 84,
+ -1, 59, 83, -1, 67, 86, 39, -1, 31, 5,
+ 88, 39, -1, 36, 39, -1, 68, 89, 88, 39,
+ -1, 33, 90, 88, 39, -1, 22, 90, 88, 39,
+ -1, 32, 91, 91, 88, 39, -1, 27, 39, -1,
+ 7, 39, -1, 61, 65, -1, 87, -1, 62, 54,
+ 63, -1, -1, 65, 66, -1, 65, 84, -1, 65,
+ 83, -1, 31, 5, 88, 39, -1, 12, 90, 88,
+ 39, -1, 6, -1, 37, -1, 23, -1, 20, -1,
+ 35, -1, 12, -1, 13, -1, 14, -1, 21, 89,
+ 39, -1, 87, -1, 69, 53, 70, -1, 69, 54,
+ 70, -1, 25, 5, 39, -1, 73, 77, -1, 87,
+ -1, 74, 53, 75, -1, -1, 77, 85, -1, 77,
+ 84, -1, 34, 5, 39, -1, 10, 5, 39, -1,
+ 79, 81, -1, -1, 81, 84, -1, 19, 39, -1,
+ 82, 3, -1, 15, 28, 89, 39, -1, 38, 88,
+ 39, -1, -1, 5, 88, -1, 18, 39, -1, 16,
+ 39, -1, 17, 39, -1, -1, 21, 89, -1, 91,
+ -1, 91, 48, 91, -1, 91, 47, 91, -1, 91,
+ 46, 91, -1, 91, 45, 91, -1, 91, 44, 91,
+ -1, 91, 43, 91, -1, 29, 89, 8, -1, 49,
+ 89, -1, 89, 41, 89, -1, 89, 42, 89, -1,
+ 4, -1, 90, -1, 5, -1, 4, 93, 94, 39,
+ -1, 44, -1, 9, -1, 30, -1, -1, 40, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 108, 108, 108, 112, 117, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 131, 133, 134, 135,
+ 136, 141, 147, 175, 181, 190, 192, 193, 194, 197,
+ 203, 209, 215, 224, 230, 236, 242, 252, 263, 276,
+ 286, 289, 291, 292, 293, 296, 302, 309, 310, 311,
+ 312, 313, 316, 317, 318, 322, 330, 338, 341, 346,
+ 353, 358, 366, 369, 371, 372, 375, 384, 391, 394,
+ 396, 401, 407, 425, 432, 439, 441, 446, 447, 448,
+ 451, 452, 455, 456, 457, 458, 459, 460, 461, 462,
+ 463, 464, 465, 469, 471, 472, 477, 480, 481, 482,
+ 486, 487
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_HELPTEXT", "T_WORD", "T_WORD_QUOTE",
+ "T_BOOL", "T_CHOICE", "T_CLOSE_PAREN", "T_COLON_EQUAL", "T_COMMENT",
+ "T_CONFIG", "T_DEFAULT", "T_DEF_BOOL", "T_DEF_TRISTATE", "T_DEPENDS",
+ "T_ENDCHOICE", "T_ENDIF", "T_ENDMENU", "T_HELP", "T_HEX", "T_IF",
+ "T_IMPLY", "T_INT", "T_MAINMENU", "T_MENU", "T_MENUCONFIG", "T_MODULES",
+ "T_ON", "T_OPEN_PAREN", "T_PLUS_EQUAL", "T_PROMPT", "T_RANGE",
+ "T_SELECT", "T_SOURCE", "T_STRING", "T_TRANSITIONAL", "T_TRISTATE",
+ "T_VISIBLE", "T_EOL", "T_ASSIGN_VAL", "T_OR", "T_AND", "T_UNEQUAL",
+ "T_EQUAL", "T_GREATER_EQUAL", "T_GREATER", "T_LESS_EQUAL", "T_LESS",
+ "T_NOT", "$accept", "input", "mainmenu_stmt", "stmt_list",
+ "stmt_list_in_choice", "config_entry_start", "config_stmt",
+ "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+ "config_option", "choice", "choice_entry", "choice_end", "choice_stmt",
+ "choice_option_list", "choice_option", "type", "default", "if_entry",
+ "if_end", "if_stmt", "if_stmt_in_choice", "menu", "menu_entry",
+ "menu_end", "menu_stmt", "menu_option_list", "source_stmt", "comment",
+ "comment_stmt", "comment_option_list", "help_start", "help", "depends",
+ "visible", "prompt_stmt_opt", "end", "if_expr", "expr",
+ "nonconst_symbol", "symbol", "assignment_stmt", "assign_op",
+ "assign_val", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 50, 51, 51, 52, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 54, 54, 54, 54,
+ 54, 55, 56, 57, 58, 59, 59, 59, 59, 60,
+ 60, 60, 60, 60, 60, 60, 60, 61, 62, 63,
+ 64, 65, 65, 65, 65, 66, 66, 67, 67, 67,
+ 67, 67, 68, 68, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 77, 77, 78, 79, 80, 81,
+ 81, 82, 83, 84, 85, 86, 86, 87, 87, 87,
+ 88, 88, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 90, 91, 91, 92, 93, 93, 93,
+ 94, 94
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 1, 3, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 4, 3, 0, 2, 2, 2,
+ 3, 3, 2, 3, 2, 0, 2, 2, 2, 3,
+ 4, 2, 4, 4, 4, 5, 2, 2, 2, 1,
+ 3, 0, 2, 2, 2, 4, 4, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 1, 3, 3, 3,
+ 2, 1, 3, 0, 2, 2, 3, 3, 2, 0,
+ 2, 2, 2, 4, 3, 0, 2, 2, 2, 2,
+ 0, 2, 1, 3, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 1, 1, 1, 4, 1, 1, 1,
+ 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 5, 0, 0, 5, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 25, 9, 25,
+ 12, 41, 16, 7, 5, 10, 63, 5, 11, 13,
+ 69, 8, 6, 4, 15, 0, 98, 99, 97, 100,
+ 37, 0, 93, 0, 95, 0, 0, 0, 94, 82,
+ 0, 0, 0, 22, 24, 38, 0, 0, 60, 0,
+ 68, 14, 101, 0, 67, 21, 0, 90, 55, 0,
+ 0, 0, 0, 0, 0, 0, 0, 59, 23, 66,
+ 47, 52, 53, 54, 0, 0, 50, 0, 49, 0,
+ 0, 0, 0, 51, 0, 48, 26, 75, 0, 0,
+ 28, 27, 0, 0, 42, 44, 43, 0, 0, 0,
+ 0, 18, 40, 16, 19, 17, 39, 57, 56, 80,
+ 65, 64, 62, 61, 70, 96, 89, 91, 92, 88,
+ 87, 86, 85, 84, 83, 0, 71, 80, 36, 80,
+ 0, 80, 31, 80, 0, 80, 72, 80, 80, 20,
+ 78, 79, 77, 0, 0, 0, 0, 0, 0, 80,
+ 0, 76, 29, 0, 0, 0, 58, 81, 74, 73,
+ 34, 30, 0, 33, 32, 46, 45, 35
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 2, 3, 4, 56, 17, 18, 19, 20, 53,
+ 96, 21, 22, 112, 23, 55, 104, 97, 98, 24,
+ 117, 25, 114, 26, 27, 122, 28, 58, 29, 30,
+ 31, 60, 99, 100, 101, 121, 144, 118, 155, 47,
+ 48, 49, 32, 39, 63
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -63
+static const yytype_int16 yypact[] =
+{
+ 4, 15, 26, -63, 35, 9, -63, 63, 23, 14,
+ 29, 42, 61, 2, 67, 61, 72, -63, -63, -63,
+ -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
+ -63, -63, -63, -63, -63, 48, -63, -63, -63, 39,
+ -63, 53, -63, 57, -63, 2, 2, 52, -63, 124,
+ 59, 64, 68, 117, 117, 40, 65, 101, 3, 101,
+ 89, -63, -63, 71, -63, -63, 8, -63, -63, 2,
+ 2, 17, 17, 17, 17, 17, 17, -63, -63, -63,
+ -63, -63, -63, -63, 78, 75, -63, 61, -63, 81,
+ 116, 17, 61, -63, 85, -63, -63, 120, 2, 125,
+ -63, -63, 61, 128, -63, -63, -63, 95, 99, 102,
+ 103, -63, -63, -63, -63, -63, -63, -63, -63, 122,
+ -63, -63, -63, -63, -63, -63, -63, 104, -63, -63,
+ -63, -63, -63, -63, -63, 2, -63, 122, -63, 122,
+ 17, 122, -63, 122, 106, -4, -63, 122, 122, -63,
+ -63, -63, -63, 65, 2, 108, 74, 112, 119, 122,
+ 121, -63, -63, 123, 134, 135, -63, -8, -63, -63,
+ -63, -63, 136, -63, -63, -63, -63, -63
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -63, -63, -63, 16, 43, -63, -54, -63, -63, 145,
+ -63, -63, -63, -63, -63, -63, -63, -63, -63, -53,
+ 25, -63, -63, -63, -63, -63, -63, -63, -63, -63,
+ -52, -63, -63, 126, -28, -63, -63, -2, 18, -45,
+ -7, -62, -63, -63, -63
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -4
+static const yytype_int16 yytable[] =
+{
+ 66, 67, 111, 113, 115, 43, 42, 44, 51, 129,
+ 130, 131, 132, 133, 134, 35, 126, 154, 84, 7,
+ 5, 42, 44, 36, 127, 128, 6, 106, 1, 140,
+ 120, 45, 124, 69, 70, -3, 8, 69, 70, 9,
+ 57, 119, 10, 59, 37, 11, 12, 41, 33, 69,
+ 70, 46, 102, 145, 116, 84, 13, 123, 38, 85,
+ 14, 15, 34, -2, 8, 42, 107, 9, 40, 16,
+ 10, 103, 50, 11, 12, 11, 12, 52, 159, 62,
+ 137, 108, 109, 110, 13, 141, 13, 61, 14, 15,
+ 156, 68, 64, 69, 70, 147, 65, 16, 77, 111,
+ 113, 115, 8, 78, 84, 9, 135, 79, 10, 167,
+ 125, 11, 12, 169, 136, 69, 70, 108, 109, 110,
+ 138, 139, 13, 80, 142, 143, 14, 15, 146, 81,
+ 82, 83, 84, 148, 149, 16, 85, 86, 150, 87,
+ 88, 151, 152, 154, 89, 162, 70, 168, 90, 91,
+ 92, 170, 93, 94, 95, 157, 153, 158, 171, 160,
+ 173, 161, 174, 163, 54, 164, 165, 71, 72, 73,
+ 74, 75, 76, 175, 176, 177, 0, 172, 166, 0,
+ 0, 105
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 45, 46, 56, 56, 56, 12, 4, 5, 15, 71,
+ 72, 73, 74, 75, 76, 1, 8, 21, 15, 3,
+ 5, 4, 5, 9, 69, 70, 0, 55, 24, 91,
+ 58, 29, 60, 41, 42, 0, 1, 41, 42, 4,
+ 24, 38, 7, 27, 30, 10, 11, 5, 39, 41,
+ 42, 49, 12, 98, 56, 15, 21, 59, 44, 19,
+ 25, 26, 39, 0, 1, 4, 1, 4, 39, 34,
+ 7, 31, 5, 10, 11, 10, 11, 5, 140, 40,
+ 87, 16, 17, 18, 21, 92, 21, 39, 25, 26,
+ 135, 39, 39, 41, 42, 102, 39, 34, 39, 153,
+ 153, 153, 1, 39, 15, 4, 28, 39, 7, 154,
+ 39, 10, 11, 39, 39, 41, 42, 16, 17, 18,
+ 39, 5, 21, 6, 39, 5, 25, 26, 3, 12,
+ 13, 14, 15, 5, 39, 34, 19, 20, 39, 22,
+ 23, 39, 39, 21, 27, 39, 42, 39, 31, 32,
+ 33, 39, 35, 36, 37, 137, 113, 139, 39, 141,
+ 39, 143, 39, 145, 19, 147, 148, 43, 44, 45,
+ 46, 47, 48, 39, 39, 39, -1, 159, 153, -1,
+ -1, 55
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 24, 51, 52, 53, 5, 0, 53, 1, 4,
+ 7, 10, 11, 21, 25, 26, 34, 55, 56, 57,
+ 58, 61, 62, 64, 69, 71, 73, 74, 76, 78,
+ 79, 80, 92, 39, 39, 1, 9, 30, 44, 93,
+ 39, 5, 4, 90, 5, 29, 49, 89, 90, 91,
+ 5, 90, 5, 59, 59, 65, 54, 53, 77, 53,
+ 81, 39, 40, 94, 39, 39, 89, 89, 39, 41,
+ 42, 43, 44, 45, 46, 47, 48, 39, 39, 39,
+ 6, 12, 13, 14, 15, 19, 20, 22, 23, 27,
+ 31, 32, 33, 35, 36, 37, 60, 67, 68, 82,
+ 83, 84, 12, 31, 66, 83, 84, 1, 16, 17,
+ 18, 56, 63, 69, 72, 80, 87, 70, 87, 38,
+ 84, 85, 75, 87, 84, 39, 8, 89, 89, 91,
+ 91, 91, 91, 91, 91, 28, 39, 90, 39, 5,
+ 91, 90, 39, 5, 86, 89, 3, 90, 5, 39,
+ 39, 39, 39, 54, 21, 88, 89, 88, 88, 91,
+ 88, 88, 39, 88, 88, 88, 70, 89, 39, 39,
+ 39, 39, 88, 39, 39, 39, 39, 39
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+ case 62: /* "choice_entry" */
+#line 100 "parser.y"
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->filename, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+#line 1317 "parser.tab.c"
+ break;
+ case 69: /* "if_entry" */
+#line 100 "parser.y"
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->filename, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+#line 1327 "parser.tab.c"
+ break;
+ case 74: /* "menu_entry" */
+#line 100 "parser.y"
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->filename, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+#line 1337 "parser.tab.c"
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 113 "parser.y"
+ {
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+;}
+ break;
+
+ case 14:
+#line 127 "parser.y"
+ { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+ break;
+
+ case 15:
+#line 128 "parser.y"
+ { zconf_error("invalid statement"); ;}
+ break;
+
+ case 20:
+#line 136 "parser.y"
+ { zconf_error("invalid statement"); ;}
+ break;
+
+ case 21:
+#line 142 "parser.y"
+ {
+ menu_add_entry((yyvsp[(2) - (3)].symbol), M_NORMAL);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, (yyvsp[(2) - (3)].symbol)->name);
+;}
+ break;
+
+ case 22:
+#line 148 "parser.y"
+ {
+ if (current_choice) {
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ if (current_entry->sym->type != S_BOOLEAN) {
+ fprintf(stderr, "%s:%d: error: choice member must be bool\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ /*
+ * If the same symbol appears twice in a choice block, the list
+ * node would be added twice, leading to a broken linked list.
+ * list_empty() ensures that this symbol has not yet added.
+ */
+ if (list_empty(&current_entry->sym->choice_link))
+ list_add_tail(&current_entry->sym->choice_link,
+ &current_choice->choice_members);
+ }
+
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 23:
+#line 176 "parser.y"
+ {
+ menu_add_entry((yyvsp[(2) - (3)].symbol), M_MENU);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, (yyvsp[(2) - (3)].symbol)->name);
+;}
+ break;
+
+ case 24:
+#line 182 "parser.y"
+ {
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconf_error("menuconfig statement without prompt");
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 29:
+#line 198 "parser.y"
+ {
+ menu_set_type((yyvsp[(1) - (3)].type));
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, (yyvsp[(1) - (3)].type));
+;}
+ break;
+
+ case 30:
+#line 204 "parser.y"
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 31:
+#line 210 "parser.y"
+ {
+ current_entry->sym->flags |= SYMBOL_TRANS;
+ printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 32:
+#line 216 "parser.y"
+ {
+ menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+ if ((yyvsp[(1) - (4)].type) != S_UNKNOWN)
+ menu_set_type((yyvsp[(1) - (4)].type));
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
+ (yyvsp[(1) - (4)].type));
+;}
+ break;
+
+ case 33:
+#line 225 "parser.y"
+ {
+ menu_add_symbol(P_SELECT, (yyvsp[(2) - (4)].symbol), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 34:
+#line 231 "parser.y"
+ {
+ menu_add_symbol(P_IMPLY, (yyvsp[(2) - (4)].symbol), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 35:
+#line 237 "parser.y"
+ {
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+ printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 36:
+#line 243 "parser.y"
+ {
+ 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 37:
+#line 253 "parser.y"
+ {
+ struct symbol *sym = sym_lookup(NULL, 0);
+
+ menu_add_entry(sym, M_CHOICE);
+ menu_set_type(S_BOOLEAN);
+ INIT_LIST_HEAD(&current_entry->choice_members);
+
+ printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 38:
+#line 264 "parser.y"
+ {
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ (yyval.menu) = menu_add_menu();
+
+ current_choice = current_entry;
+;}
+ break;
+
+ case 39:
+#line 277 "parser.y"
+ {
+ current_choice = NULL;
+
+ if (zconf_endtoken((yyvsp[(1) - (1)].string), "choice")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
+ }
+;}
+ break;
+
+ case 45:
+#line 297 "parser.y"
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 46:
+#line 303 "parser.y"
+ {
+ menu_add_symbol(P_DEFAULT, (yyvsp[(2) - (4)].symbol), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 47:
+#line 309 "parser.y"
+ { (yyval.type) = S_BOOLEAN; ;}
+ break;
+
+ case 48:
+#line 310 "parser.y"
+ { (yyval.type) = S_TRISTATE; ;}
+ break;
+
+ case 49:
+#line 311 "parser.y"
+ { (yyval.type) = S_INT; ;}
+ break;
+
+ case 50:
+#line 312 "parser.y"
+ { (yyval.type) = S_HEX; ;}
+ break;
+
+ case 51:
+#line 313 "parser.y"
+ { (yyval.type) = S_STRING; ;}
+ break;
+
+ case 52:
+#line 316 "parser.y"
+ { (yyval.type) = S_UNKNOWN; ;}
+ break;
+
+ case 53:
+#line 317 "parser.y"
+ { (yyval.type) = S_BOOLEAN; ;}
+ break;
+
+ case 54:
+#line 318 "parser.y"
+ { (yyval.type) = S_TRISTATE; ;}
+ break;
+
+ case 55:
+#line 323 "parser.y"
+ {
+ printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
+ menu_add_entry(NULL, M_IF);
+ menu_add_dep((yyvsp[(2) - (3)].expr));
+ (yyval.menu) = menu_add_menu();
+;}
+ break;
+
+ case 56:
+#line 331 "parser.y"
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].string), "if")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
+ }
+;}
+ break;
+
+ case 59:
+#line 347 "parser.y"
+ {
+ menu_add_entry(NULL, M_MENU);
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 60:
+#line 354 "parser.y"
+ {
+ (yyval.menu) = menu_add_menu();
+;}
+ break;
+
+ case 61:
+#line 359 "parser.y"
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].string), "menu")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
+ }
+;}
+ break;
+
+ case 66:
+#line 376 "parser.y"
+ {
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, (yyvsp[(2) - (3)].string));
+ zconf_nextfile((yyvsp[(2) - (3)].string));
+ free((yyvsp[(2) - (3)].string));
+;}
+ break;
+
+ case 67:
+#line 385 "parser.y"
+ {
+ menu_add_entry(NULL, M_COMMENT);
+ menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 71:
+#line 402 "parser.y"
+ {
+ printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
+ zconf_starthelp();
+;}
+ break;
+
+ case 72:
+#line 408 "parser.y"
+ {
+ if (current_entry->help) {
+ free(current_entry->help);
+ zconf_error("'%s' defined with more than one help text",
+ current_entry->sym->name ?: "<choice>");
+ }
+
+ /* Is the help text empty or all whitespace? */
+ if ((yyvsp[(2) - (2)].string)[strspn((yyvsp[(2) - (2)].string), " \f\n\r\t\v")] == '\0')
+ zconf_error("'%s' defined with blank help text",
+ current_entry->sym->name ?: "<choice>");
+
+ current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+ break;
+
+ case 73:
+#line 426 "parser.y"
+ {
+ menu_add_dep((yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
+;}
+ break;
+
+ case 74:
+#line 433 "parser.y"
+ {
+ menu_add_visibility((yyvsp[(2) - (3)].expr));
+;}
+ break;
+
+ case 76:
+#line 442 "parser.y"
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+ break;
+
+ case 77:
+#line 446 "parser.y"
+ { (yyval.string) = "menu"; ;}
+ break;
+
+ case 78:
+#line 447 "parser.y"
+ { (yyval.string) = "choice"; ;}
+ break;
+
+ case 79:
+#line 448 "parser.y"
+ { (yyval.string) = "if"; ;}
+ break;
+
+ case 80:
+#line 451 "parser.y"
+ { (yyval.expr) = NULL; ;}
+ break;
+
+ case 81:
+#line 452 "parser.y"
+ { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+ break;
+
+ case 82:
+#line 455 "parser.y"
+ { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+ break;
+
+ case 83:
+#line 456 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 84:
+#line 457 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 85:
+#line 458 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 86:
+#line 459 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 87:
+#line 460 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 88:
+#line 461 "parser.y"
+ { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 89:
+#line 462 "parser.y"
+ { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+ break;
+
+ case 90:
+#line 463 "parser.y"
+ { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+ break;
+
+ case 91:
+#line 464 "parser.y"
+ { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+ break;
+
+ case 92:
+#line 465 "parser.y"
+ { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+ break;
+
+ case 93:
+#line 469 "parser.y"
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+ break;
+
+ case 95:
+#line 472 "parser.y"
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+ break;
+
+ case 96:
+#line 477 "parser.y"
+ { variable_add((yyvsp[(1) - (4)].string), (yyvsp[(3) - (4)].string), (yyvsp[(2) - (4)].flavor)); free((yyvsp[(1) - (4)].string)); free((yyvsp[(3) - (4)].string)); ;}
+ break;
+
+ case 97:
+#line 480 "parser.y"
+ { (yyval.flavor) = VAR_RECURSIVE; ;}
+ break;
+
+ case 98:
+#line 481 "parser.y"
+ { (yyval.flavor) = VAR_SIMPLE; ;}
+ break;
+
+ case 99:
+#line 482 "parser.y"
+ { (yyval.flavor) = VAR_APPEND; ;}
+ break;
+
+ case 100:
+#line 486 "parser.y"
+ { (yyval.string) = xstrdup(""); ;}
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 2118 "parser.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 490 "parser.y"
+
+
+/**
+ * transitional_check_sanity - check transitional symbols have no other
+ * properties
+ *
+ * @menu: menu of the potentially transitional symbol
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int transitional_check_sanity(const struct menu *menu)
+{
+ struct property *prop;
+
+ if (!menu->sym || !(menu->sym->flags & SYMBOL_TRANS))
+ return 0;
+
+ /* Check for depends and visible conditions. */
+ if ((menu->dep && !expr_is_yes(menu->dep)) ||
+ (menu->visibility && !expr_is_yes(menu->visibility))) {
+ fprintf(stderr, "%s:%d: error: %s",
+ menu->filename, menu->lineno,
+ "transitional symbols can only have help sections\n");
+ return -1;
+ }
+
+ /* Check for any property other than "help". */
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type != P_COMMENT) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "transitional symbols can only have help sections\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * choice_check_sanity - check sanity of a choice member
+ *
+ * @menu: menu of the choice member
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int choice_check_sanity(const struct menu *menu)
+{
+ struct property *prop;
+ int ret = 0;
+
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "defaults for choice values not supported\n");
+ ret = -1;
+ }
+
+ if (prop->menu != menu && prop->type == P_PROMPT &&
+ prop->menu->parent != menu->parent) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "choice value has a prompt outside its choice group\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void conf_parse(const char *name)
+{
+ struct menu *menu;
+
+ autoconf_cmd = str_new();
+
+ str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
+
+ zconf_initscan(name);
+
+ _menu_init();
+
+ yyparse();
+
+ str_printf(&autoconf_cmd,
+ "\n"
+ "$(autoconfig): $(deps_config)\n"
+ "$(deps_config): ;\n");
+
+ env_write_dep(&autoconf_cmd);
+
+ /* Variables are expanded in the parse phase. We can free them here. */
+ variable_all_del();
+
+ if (yynerrs)
+ exit(1);
+ if (!modules_sym)
+ modules_sym = &symbol_no;
+
+ if (!menu_has_prompt(&rootmenu)) {
+ current_entry = &rootmenu;
+ menu_add_prompt(P_MENU, "Main menu", NULL);
+ }
+
+ menu_finalize();
+
+ menu_for_each_entry(menu) {
+ struct menu *child;
+
+ if (menu->sym && sym_check_deps(menu->sym))
+ yynerrs++;
+
+ if (transitional_check_sanity(menu))
+ yynerrs++;
+
+ if (menu->sym && sym_is_choice(menu->sym)) {
+ menu_for_each_sub_entry(child, menu)
+ if (child->sym && choice_check_sanity(child))
+ yynerrs++;
+ }
+ }
+
+ if (yynerrs)
+ exit(1);
+ conf_set_changed(true);
+}
+
+static bool zconf_endtoken(const char *tokenname,
+ const char *expected_tokenname)
+{
+ if (strcmp(tokenname, expected_tokenname)) {
+ zconf_error("unexpected '%s' within %s block",
+ tokenname, expected_tokenname);
+ yynerrs++;
+ return false;
+ }
+ if (strcmp(current_menu->filename, cur_filename)) {
+ zconf_error("'%s' in different file than '%s'",
+ tokenname, expected_tokenname);
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->filename, current_menu->lineno,
+ expected_tokenname);
+ yynerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ yynerrs++;
+ fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void yyerror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, const struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" bool\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_IMPLY:
+ fputs( " imply ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
diff --git a/scripts/kconfig/parser.tab.h b/scripts/kconfig/parser.tab.h
new file mode 100644
index 00000000..7cccc332
--- /dev/null
+++ b/scripts/kconfig/parser.tab.h
@@ -0,0 +1,163 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_HELPTEXT = 258,
+ T_WORD = 259,
+ T_WORD_QUOTE = 260,
+ T_BOOL = 261,
+ T_CHOICE = 262,
+ T_CLOSE_PAREN = 263,
+ T_COLON_EQUAL = 264,
+ T_COMMENT = 265,
+ T_CONFIG = 266,
+ T_DEFAULT = 267,
+ T_DEF_BOOL = 268,
+ T_DEF_TRISTATE = 269,
+ T_DEPENDS = 270,
+ T_ENDCHOICE = 271,
+ T_ENDIF = 272,
+ T_ENDMENU = 273,
+ T_HELP = 274,
+ T_HEX = 275,
+ T_IF = 276,
+ T_IMPLY = 277,
+ T_INT = 278,
+ T_MAINMENU = 279,
+ T_MENU = 280,
+ T_MENUCONFIG = 281,
+ T_MODULES = 282,
+ T_ON = 283,
+ T_OPEN_PAREN = 284,
+ T_PLUS_EQUAL = 285,
+ T_PROMPT = 286,
+ T_RANGE = 287,
+ T_SELECT = 288,
+ T_SOURCE = 289,
+ T_STRING = 290,
+ T_TRANSITIONAL = 291,
+ T_TRISTATE = 292,
+ T_VISIBLE = 293,
+ T_EOL = 294,
+ T_ASSIGN_VAL = 295,
+ T_OR = 296,
+ T_AND = 297,
+ T_UNEQUAL = 298,
+ T_EQUAL = 299,
+ T_GREATER_EQUAL = 300,
+ T_GREATER = 301,
+ T_LESS_EQUAL = 302,
+ T_LESS = 303,
+ T_NOT = 304
+ };
+#endif
+/* Tokens. */
+#define T_HELPTEXT 258
+#define T_WORD 259
+#define T_WORD_QUOTE 260
+#define T_BOOL 261
+#define T_CHOICE 262
+#define T_CLOSE_PAREN 263
+#define T_COLON_EQUAL 264
+#define T_COMMENT 265
+#define T_CONFIG 266
+#define T_DEFAULT 267
+#define T_DEF_BOOL 268
+#define T_DEF_TRISTATE 269
+#define T_DEPENDS 270
+#define T_ENDCHOICE 271
+#define T_ENDIF 272
+#define T_ENDMENU 273
+#define T_HELP 274
+#define T_HEX 275
+#define T_IF 276
+#define T_IMPLY 277
+#define T_INT 278
+#define T_MAINMENU 279
+#define T_MENU 280
+#define T_MENUCONFIG 281
+#define T_MODULES 282
+#define T_ON 283
+#define T_OPEN_PAREN 284
+#define T_PLUS_EQUAL 285
+#define T_PROMPT 286
+#define T_RANGE 287
+#define T_SELECT 288
+#define T_SOURCE 289
+#define T_STRING 290
+#define T_TRANSITIONAL 291
+#define T_TRISTATE 292
+#define T_VISIBLE 293
+#define T_EOL 294
+#define T_ASSIGN_VAL 295
+#define T_OR 296
+#define T_AND 297
+#define T_UNEQUAL 298
+#define T_EQUAL 299
+#define T_GREATER_EQUAL 300
+#define T_GREATER 301
+#define T_LESS_EQUAL 302
+#define T_LESS 303
+#define T_NOT 304
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 36 "parser.y"
+{
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ enum symbol_type type;
+ enum variable_flavor flavor;
+}
+/* Line 1529 of yacc.c. */
+#line 156 "parser.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
new file mode 100644
index 00000000..42919e15
--- /dev/null
+++ b/scripts/kconfig/parser.y
@@ -0,0 +1,802 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%{
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <xalloc.h>
+#include "lkc.h"
+#include "internal.h"
+#include "preprocess.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+static void yyerror(const char *err);
+static void zconf_error(const char *err, ...);
+static bool zconf_endtoken(const char *tokenname,
+ const char *expected_tokenname);
+
+struct menu *current_menu, *current_entry, *current_choice;
+
+%}
+
+%union
+{
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ enum symbol_type type;
+ enum variable_flavor flavor;
+}
+
+%token <string> T_HELPTEXT
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%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_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_PLUS_EQUAL
+%token T_PROMPT
+%token T_RANGE
+%token T_SELECT
+%token T_SOURCE
+%token T_STRING
+%token T_TRANSITIONAL
+%token T_TRISTATE
+%token T_VISIBLE
+%token T_EOL
+%token <string> T_ASSIGN_VAL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
+%nonassoc T_NOT
+
+%type <symbol> nonconst_symbol
+%type <symbol> symbol
+%type <type> type default
+%type <expr> expr
+%type <expr> if_expr
+%type <string> end
+%type <menu> if_entry menu_entry choice_entry
+%type <string> assign_val
+%type <flavor> assign_op
+
+%destructor {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ $$->filename, $$->lineno);
+ if (current_menu == $$)
+ menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%%
+input: mainmenu_stmt stmt_list | stmt_list;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL
+{
+ menu_add_prompt(P_MENU, $2, NULL);
+};
+
+stmt_list:
+ /* empty */
+ | stmt_list assignment_stmt
+ | stmt_list choice_stmt
+ | stmt_list comment_stmt
+ | stmt_list config_stmt
+ | stmt_list if_stmt
+ | stmt_list menu_stmt
+ | stmt_list menuconfig_stmt
+ | stmt_list source_stmt
+ | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
+ | stmt_list error T_EOL { zconf_error("invalid statement"); }
+;
+
+stmt_list_in_choice:
+ /* empty */
+ | stmt_list_in_choice comment_stmt
+ | stmt_list_in_choice config_stmt
+ | stmt_list_in_choice if_stmt_in_choice
+ | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); }
+;
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG nonconst_symbol T_EOL
+{
+ menu_add_entry($2, M_NORMAL);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+ if (current_choice) {
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ if (current_entry->sym->type != S_BOOLEAN) {
+ fprintf(stderr, "%s:%d: error: choice member must be bool\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ /*
+ * If the same symbol appears twice in a choice block, the list
+ * node would be added twice, leading to a broken linked list.
+ * list_empty() ensures that this symbol has not yet added.
+ */
+ if (list_empty(&current_entry->sym->choice_link))
+ list_add_tail(&current_entry->sym->choice_link,
+ &current_choice->choice_members);
+ }
+
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
+};
+
+menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
+{
+ menu_add_entry($2, M_MENU);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconf_error("menuconfig statement without prompt");
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
+};
+
+config_option_list:
+ /* empty */
+ | config_option_list config_option
+ | config_option_list depends
+ | config_option_list help
+;
+
+config_option: type prompt_stmt_opt T_EOL
+{
+ menu_set_type($1);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
+};
+
+config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
+};
+
+config_option: T_TRANSITIONAL T_EOL
+{
+ current_entry->sym->flags |= SYMBOL_TRANS;
+ printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename, cur_lineno);
+};
+
+config_option: default expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ if ($1 != S_UNKNOWN)
+ menu_set_type($1);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
+ $1);
+};
+
+config_option: T_SELECT nonconst_symbol if_expr T_EOL
+{
+ menu_add_symbol(P_SELECT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
+};
+
+config_option: T_IMPLY nonconst_symbol if_expr T_EOL
+{
+ menu_add_symbol(P_IMPLY, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+ printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
+};
+
+config_option: T_MODULES T_EOL
+{
+ 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;
+};
+
+/* choice entry */
+
+choice: T_CHOICE T_EOL
+{
+ struct symbol *sym = sym_lookup(NULL, 0);
+
+ menu_add_entry(sym, M_CHOICE);
+ menu_set_type(S_BOOLEAN);
+ INIT_LIST_HEAD(&current_entry->choice_members);
+
+ printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
+};
+
+choice_entry: choice choice_option_list
+{
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ $$ = menu_add_menu();
+
+ current_choice = current_entry;
+};
+
+choice_end: end
+{
+ current_choice = NULL;
+
+ if (zconf_endtoken($1, "choice")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
+ }
+};
+
+choice_stmt: choice_entry stmt_list_in_choice choice_end
+;
+
+choice_option_list:
+ /* empty */
+ | choice_option_list choice_option
+ | choice_option_list depends
+ | choice_option_list help
+;
+
+choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
+};
+
+choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
+{
+ menu_add_symbol(P_DEFAULT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
+};
+
+type:
+ T_BOOL { $$ = S_BOOLEAN; }
+ | T_TRISTATE { $$ = S_TRISTATE; }
+ | T_INT { $$ = S_INT; }
+ | T_HEX { $$ = S_HEX; }
+ | T_STRING { $$ = S_STRING; }
+
+default:
+ T_DEFAULT { $$ = S_UNKNOWN; }
+ | T_DEF_BOOL { $$ = S_BOOLEAN; }
+ | T_DEF_TRISTATE { $$ = S_TRISTATE; }
+
+/* if entry */
+
+if_entry: T_IF expr T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
+ menu_add_entry(NULL, M_IF);
+ menu_add_dep($2);
+ $$ = menu_add_menu();
+};
+
+if_end: end
+{
+ if (zconf_endtoken($1, "if")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
+ }
+};
+
+if_stmt: if_entry stmt_list if_end
+;
+
+if_stmt_in_choice: if_entry stmt_list_in_choice if_end
+;
+
+/* menu entry */
+
+menu: T_MENU T_WORD_QUOTE T_EOL
+{
+ menu_add_entry(NULL, M_MENU);
+ menu_add_prompt(P_MENU, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
+};
+
+menu_entry: menu menu_option_list
+{
+ $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+ if (zconf_endtoken($1, "menu")) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
+ }
+};
+
+menu_stmt: menu_entry stmt_list menu_end
+;
+
+menu_option_list:
+ /* empty */
+ | menu_option_list visible
+ | menu_option_list depends
+;
+
+source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2);
+ zconf_nextfile($2);
+ free($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT T_WORD_QUOTE T_EOL
+{
+ menu_add_entry(NULL, M_COMMENT);
+ menu_add_prompt(P_COMMENT, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
+};
+
+comment_stmt: comment comment_option_list
+;
+
+comment_option_list:
+ /* empty */
+ | comment_option_list depends
+;
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
+ zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+ if (current_entry->help) {
+ free(current_entry->help);
+ zconf_error("'%s' defined with more than one help text",
+ current_entry->sym->name ?: "<choice>");
+ }
+
+ /* Is the help text empty or all whitespace? */
+ if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
+ zconf_error("'%s' defined with blank help text",
+ current_entry->sym->name ?: "<choice>");
+
+ current_entry->help = $2;
+};
+
+/* depends option */
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+ menu_add_dep($3);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
+};
+
+/* visibility option */
+visible: T_VISIBLE if_expr T_EOL
+{
+ menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+ /* empty */
+ | T_WORD_QUOTE if_expr
+{
+ menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+end: T_ENDMENU T_EOL { $$ = "menu"; }
+ | T_ENDCHOICE T_EOL { $$ = "choice"; }
+ | T_ENDIF T_EOL { $$ = "if"; }
+;
+
+if_expr: /* empty */ { $$ = NULL; }
+ | T_IF expr { $$ = $2; }
+;
+
+expr: symbol { $$ = expr_alloc_symbol($1); }
+ | symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); }
+ | symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); }
+ | symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); }
+ | symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); }
+ | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+ | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+ | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
+ | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
+ | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
+ | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+/* 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); }
+;
+
+/* 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
+;
+
+%%
+
+/**
+ * transitional_check_sanity - check transitional symbols have no other
+ * properties
+ *
+ * @menu: menu of the potentially transitional symbol
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int transitional_check_sanity(const struct menu *menu)
+{
+ struct property *prop;
+
+ if (!menu->sym || !(menu->sym->flags & SYMBOL_TRANS))
+ return 0;
+
+ /* Check for depends and visible conditions. */
+ if ((menu->dep && !expr_is_yes(menu->dep)) ||
+ (menu->visibility && !expr_is_yes(menu->visibility))) {
+ fprintf(stderr, "%s:%d: error: %s",
+ menu->filename, menu->lineno,
+ "transitional symbols can only have help sections\n");
+ return -1;
+ }
+
+ /* Check for any property other than "help". */
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type != P_COMMENT) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "transitional symbols can only have help sections\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * choice_check_sanity - check sanity of a choice member
+ *
+ * @menu: menu of the choice member
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int choice_check_sanity(const struct menu *menu)
+{
+ struct property *prop;
+ int ret = 0;
+
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "defaults for choice values not supported\n");
+ ret = -1;
+ }
+
+ if (prop->menu != menu && prop->type == P_PROMPT &&
+ prop->menu->parent != menu->parent) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "choice value has a prompt outside its choice group\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void conf_parse(const char *name)
+{
+ struct menu *menu;
+
+ autoconf_cmd = str_new();
+
+ str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
+
+ zconf_initscan(name);
+
+ _menu_init();
+
+ yyparse();
+
+ str_printf(&autoconf_cmd,
+ "\n"
+ "$(autoconfig): $(deps_config)\n"
+ "$(deps_config): ;\n");
+
+ env_write_dep(&autoconf_cmd);
+
+ /* Variables are expanded in the parse phase. We can free them here. */
+ variable_all_del();
+
+ if (yynerrs)
+ exit(1);
+ if (!modules_sym)
+ modules_sym = &symbol_no;
+
+ if (!menu_has_prompt(&rootmenu)) {
+ current_entry = &rootmenu;
+ menu_add_prompt(P_MENU, "Main menu", NULL);
+ }
+
+ menu_finalize();
+
+ menu_for_each_entry(menu) {
+ struct menu *child;
+
+ if (menu->sym && sym_check_deps(menu->sym))
+ yynerrs++;
+
+ if (transitional_check_sanity(menu))
+ yynerrs++;
+
+ if (menu->sym && sym_is_choice(menu->sym)) {
+ menu_for_each_sub_entry(child, menu)
+ if (child->sym && choice_check_sanity(child))
+ yynerrs++;
+ }
+ }
+
+ if (yynerrs)
+ exit(1);
+ conf_set_changed(true);
+}
+
+static bool zconf_endtoken(const char *tokenname,
+ const char *expected_tokenname)
+{
+ if (strcmp(tokenname, expected_tokenname)) {
+ zconf_error("unexpected '%s' within %s block",
+ tokenname, expected_tokenname);
+ yynerrs++;
+ return false;
+ }
+ if (strcmp(current_menu->filename, cur_filename)) {
+ zconf_error("'%s' in different file than '%s'",
+ tokenname, expected_tokenname);
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->filename, current_menu->lineno,
+ expected_tokenname);
+ yynerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ yynerrs++;
+ fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void yyerror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, const struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" bool\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_IMPLY:
+ fputs( " imply ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c
new file mode 100644
index 00000000..783abcaa
--- /dev/null
+++ b/scripts/kconfig/preprocess.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <array_size.h>
+#include <list.h>
+#include <xalloc.h>
+#include "internal.h"
+#include "lkc.h"
+#include "preprocess.h"
+
+static char *expand_string_with_args(const char *in, int argc, char *argv[]);
+static char *expand_string(const char *in);
+
+static void __attribute__((noreturn)) pperror(const char *format, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", cur_filename, 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(struct gstr *s)
+{
+ struct env *e, *tmp;
+
+ list_for_each_entry_safe(e, tmp, &env_list, node) {
+ str_printf(s,
+ "\n"
+ "ifneq \"$(%s)\" \"%s\"\n"
+ "$(autoconfig): FORCE\n"
+ "endif\n",
+ e->name, e->value);
+ 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 xstrdup("");
+}
+
+static char *do_filename(int argc, char *argv[])
+{
+ return xstrdup(cur_filename);
+}
+
+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[4096];
+ 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", cur_filename, 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++;
+ }
+
+ if (new_argc >= FUNCTION_MAX_ARGS)
+ pperror("too many function arguments");
+ 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);
+}
+
+static 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/scripts/kconfig/preprocess.h b/scripts/kconfig/preprocess.h
new file mode 100644
index 00000000..a7e4a550
--- /dev/null
+++ b/scripts/kconfig/preprocess.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef PREPROCESS_H
+#define PREPROCESS_H
+
+enum variable_flavor {
+ VAR_SIMPLE,
+ VAR_RECURSIVE,
+ VAR_APPEND,
+};
+
+struct gstr;
+void env_write_dep(struct gstr *gs);
+void variable_add(const char *name, const char *value,
+ enum variable_flavor flavor);
+void variable_all_del(void);
+char *expand_dollar(const char **str);
+char *expand_one_token(const char **str);
+
+#endif /* PREPROCESS_H */
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
new file mode 100755
index 00000000..8e23faab
--- /dev/null
+++ b/scripts/kconfig/streamline_config.pl
@@ -0,0 +1,716 @@
+#!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2005-2009 - Steven Rostedt
+#
+# It's simple enough to figure out how this works.
+# If not, then you can ask me at stripconfig@goodmis.org
+#
+# What it does?
+#
+# If you have installed a Linux kernel from a distribution
+# that turns on way too many modules than you need, and
+# you only want the modules you use, then this program
+# is perfect for you.
+#
+# It gives you the ability to turn off all the modules that are
+# not loaded on your system.
+#
+# Howto:
+#
+# 1. Boot up the kernel that you want to stream line the config on.
+# 2. Change directory to the directory holding the source of the
+# kernel that you just booted.
+# 3. Copy the configuration file to this directory as .config
+# 4. Have all your devices that you need modules for connected and
+# operational (make sure that their corresponding modules are loaded)
+# 5. Run this script redirecting the output to some other file
+# like config_strip.
+# 6. Back up your old config (if you want too).
+# 7. copy the config_strip file to .config
+# 8. Run "make oldconfig"
+#
+# Now your kernel is ready to be built with only the modules that
+# are loaded.
+#
+# Here's what I did with my Debian distribution.
+#
+# cd /usr/src/linux-2.6.10
+# cp /boot/config-2.6.10-1-686-smp .config
+# ~/bin/streamline_config > config_strip
+# mv .config config_sav
+# mv config_strip .config
+# make oldconfig
+#
+use warnings;
+use strict;
+use Getopt::Long;
+
+# set the environment variable LOCALMODCONFIG_DEBUG to get
+# debug output.
+my $debugprint = 0;
+$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
+
+sub dprint {
+ return if (!$debugprint);
+ print STDERR @_;
+}
+
+my $uname = `uname -r`;
+chomp $uname;
+
+my @searchconfigs = (
+ {
+ "file" => ".config",
+ "exec" => "cat",
+ },
+ {
+ "file" => "/proc/config.gz",
+ "exec" => "zcat",
+ },
+ {
+ "file" => "/boot/config-$uname",
+ "exec" => "cat",
+ },
+ {
+ "file" => "/boot/vmlinuz-$uname",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "vmlinux",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "kernel/configs.ko",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "kernel/configs.o",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+);
+
+sub read_config {
+ foreach my $conf (@searchconfigs) {
+ my $file = $conf->{"file"};
+
+ next if ( ! -f "$file");
+
+ if (defined($conf->{"test"})) {
+ `$conf->{"test"} $conf->{"file"} 2>/dev/null`;
+ next if ($?);
+ }
+
+ my $exec = $conf->{"exec"};
+
+ print STDERR "using config: '$file'\n";
+
+ open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
+ my @x = <$infile>;
+ close $infile;
+ return @x;
+ }
+ die "No config file found";
+}
+
+my @config_file = read_config;
+
+# Parse options
+my $localmodconfig = 0;
+my $localyesconfig = 0;
+
+GetOptions("localmodconfig" => \$localmodconfig,
+ "localyesconfig" => \$localyesconfig);
+
+# Get the build source and top level Kconfig file (passed in)
+my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
+my $kconfig = $ARGV[1];
+my $lsmod_file = $ENV{'LSMOD'};
+
+my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`;
+chomp @makefiles;
+
+my %depends;
+my %selects;
+my %prompts;
+my %objects;
+my %config2kfile;
+my %defaults;
+my $var;
+my $iflevel = 0;
+my @ifdeps;
+
+# prevent recursion
+my %read_kconfigs;
+
+sub read_kconfig {
+ my ($kconfig) = @_;
+
+ my $state = "NONE";
+ my $config;
+
+ my $cont = 0;
+ my $line;
+
+ my $source = "$ksource/$kconfig";
+ my $last_source = "";
+
+ # Check for any environment variables used
+ while ($source =~ /\$\((\w+)\)/ && $last_source ne $source) {
+ my $env = $1;
+ $last_source = $source;
+ $source =~ s/\$\($env\)/$ENV{$env}/;
+ }
+
+ open(my $kinfile, '<', $source) || die "Can't open $source";
+ while (<$kinfile>) {
+ chomp;
+
+ # Make sure that lines ending with \ continue
+ if ($cont) {
+ $_ = $line . " " . $_;
+ }
+
+ if (s/\\$//) {
+ $cont = 1;
+ $line = $_;
+ next;
+ }
+
+ $cont = 0;
+
+ # collect any Kconfig sources
+ if (/^source\s+"?([^"]+)/) {
+ my $kconfig = $1;
+ # prevent reading twice.
+ if (!defined($read_kconfigs{$kconfig})) {
+ $read_kconfigs{$kconfig} = 1;
+ read_kconfig($kconfig);
+ }
+ next;
+ }
+
+ # configs found
+ if (/^\s*(menu)?config\s+(\S+)\s*$/) {
+ $state = "NEW";
+ $config = $2;
+ $config2kfile{"CONFIG_$config"} = $kconfig;
+
+ # Add depends for 'if' nesting
+ for (my $i = 0; $i < $iflevel; $i++) {
+ if ($i) {
+ $depends{$config} .= " " . $ifdeps[$i];
+ } else {
+ $depends{$config} = $ifdeps[$i];
+ }
+ $state = "DEP";
+ }
+
+ # collect the depends for the config
+ } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
+ $state = "DEP";
+ $depends{$config} = $1;
+ } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
+ $depends{$config} .= " " . $1;
+ } elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
+ my $dep = $3;
+ $defaults{$config} = 1;
+ if ($dep !~ /^\s*(y|m|n)\s*$/) {
+ $dep =~ s/.*\sif\s+//;
+ $depends{$config} .= " " . $dep;
+ dprint "Added default depends $dep to $config\n";
+ }
+
+ # Get the configs that select this config
+ } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
+ my $conf = $1;
+ if (defined($selects{$conf})) {
+ $selects{$conf} .= " " . $config;
+ } else {
+ $selects{$conf} = $config;
+ }
+
+ # configs without prompts must be selected
+ } elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) {
+ # note if the config has a prompt
+ $prompts{$config} = 1;
+
+ # Check for if statements
+ } elsif (/^if\s+(.*\S)\s*$/) {
+ my $deps = $1;
+ # remove beginning and ending non text
+ $deps =~ s/^[^a-zA-Z0-9_]*//;
+ $deps =~ s/[^a-zA-Z0-9_]*$//;
+
+ my @deps = split /[^a-zA-Z0-9_]+/, $deps;
+
+ $ifdeps[$iflevel++] = join ':', @deps;
+
+ } elsif (/^endif/) {
+
+ $iflevel-- if ($iflevel);
+
+ # stop on "help" and keywords that end a menu entry
+ } elsif (/^\s*(---)?help(---)?\s*$/ || /^(comment|choice|menu)\b/) {
+ $state = "NONE";
+ }
+ }
+ close($kinfile);
+}
+
+if ($kconfig) {
+ read_kconfig($kconfig);
+}
+
+# Makefiles can use variables to define their dependencies
+sub convert_vars {
+ my ($line, %vars) = @_;
+
+ my $process = "";
+
+ while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
+ my $start = $1;
+ my $variable = $2;
+ my $var = $3;
+
+ if (defined($vars{$var})) {
+ $process .= $start . $vars{$var};
+ } else {
+ $process .= $start . $variable;
+ }
+ }
+
+ $process .= $line;
+
+ return $process;
+}
+
+# Read all Makefiles to map the configs to the objects
+foreach my $makefile (@makefiles) {
+
+ my $line = "";
+ my %make_vars;
+
+ open(my $infile, '<', $makefile) || die "Can't open $makefile";
+ while (<$infile>) {
+ # if this line ends with a backslash, continue
+ chomp;
+ if (/^(.*)\\$/) {
+ $line .= $1;
+ next;
+ }
+
+ $line .= $_;
+ $_ = $line;
+ $line = "";
+
+ my $objs;
+
+ # Convert variables in a line (could define configs)
+ $_ = convert_vars($_, %make_vars);
+
+ # collect objects after obj-$(CONFIG_FOO_BAR)
+ if (/obj-\$[({](CONFIG_[^})]*)[)}]\s*[+:]?=\s*(.*)/) {
+ $var = $1;
+ $objs = $2;
+
+ # check if variables are set
+ } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
+ $make_vars{$1} = $2;
+ }
+ if (defined($objs)) {
+ foreach my $obj (split /\s+/,$objs) {
+ $obj =~ s/-/_/g;
+ if ($obj =~ /(.*)\.o$/) {
+ # Objects may be enabled by more than one config.
+ # Store configs in an array.
+ my @arr;
+
+ if (defined($objects{$1})) {
+ @arr = @{$objects{$1}};
+ }
+
+ $arr[$#arr+1] = $var;
+
+ # The objects have a hash mapping to a reference
+ # of an array of configs.
+ $objects{$1} = \@arr;
+ }
+ }
+ }
+ }
+ close($infile);
+}
+
+my %modules;
+my $linfile;
+
+if (defined($lsmod_file)) {
+ if ( ! -f $lsmod_file) {
+ if ( -f $ENV{'objtree'}."/".$lsmod_file) {
+ $lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
+ } else {
+ die "$lsmod_file not found";
+ }
+ }
+
+ my $otype = ( -x $lsmod_file) ? '-|' : '<';
+ open($linfile, $otype, $lsmod_file);
+
+} else {
+
+ # see what modules are loaded on this system
+ my $lsmod;
+
+ foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
+ if ( -x "$dir/lsmod" ) {
+ $lsmod = "$dir/lsmod";
+ last;
+ }
+ }
+ if (!defined($lsmod)) {
+ # try just the path
+ $lsmod = "lsmod";
+ }
+
+ open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
+}
+
+while (<$linfile>) {
+ next if (/^Module/); # Skip the first line.
+ if (/^(\S+)/) {
+ $modules{$1} = 1;
+ }
+}
+close ($linfile);
+
+# add to the configs hash all configs that are needed to enable
+# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
+# where we know we need bar.o so we add FOO to the list.
+my %configs;
+foreach my $module (keys(%modules)) {
+ if (defined($objects{$module})) {
+ my @arr = @{$objects{$module}};
+ foreach my $conf (@arr) {
+ $configs{$conf} = $module;
+ dprint "$conf added by direct ($module)\n";
+ if ($debugprint) {
+ my $c=$conf;
+ $c =~ s/^CONFIG_//;
+ if (defined($depends{$c})) {
+ dprint " deps = $depends{$c}\n";
+ } else {
+ dprint " no deps\n";
+ }
+ }
+ }
+ } else {
+ # Most likely, someone has a custom (binary?) module loaded.
+ print STDERR "$module config not found!!\n";
+ }
+}
+
+# Read the current config, and see what is enabled. We want to
+# ignore configs that we would not enable anyway.
+
+my %orig_configs;
+my $valid = "A-Za-z_0-9";
+
+foreach my $line (@config_file) {
+ $_ = $line;
+
+ if (/(CONFIG_[$valid]*)=(m|y)/) {
+ $orig_configs{$1} = $2;
+ }
+}
+
+my $repeat = 1;
+
+my $depconfig;
+
+#
+# Note, we do not care about operands (like: &&, ||, !) we want to add any
+# config that is in the depend list of another config. This script does
+# not enable configs that are not already enabled. If we come across a
+# config A that depends on !B, we can still add B to the list of depends
+# to keep on. If A was on in the original config, B would not have been
+# and B would not be turned on by this script.
+#
+sub parse_config_depends
+{
+ my ($p) = @_;
+
+ while ($p =~ /[$valid]/) {
+
+ if ($p =~ /^[^$valid]*([$valid]+)/) {
+ my $conf = "CONFIG_" . $1;
+
+ $p =~ s/^[^$valid]*[$valid]+//;
+
+ # We only need to process if the depend config is a module
+ if (!defined($orig_configs{$conf}) || $orig_configs{$conf} eq "y") {
+ next;
+ }
+
+ if (!defined($configs{$conf})) {
+ # We must make sure that this config has its
+ # dependencies met.
+ $repeat = 1; # do again
+ dprint "$conf selected by depend $depconfig\n";
+ $configs{$conf} = 1;
+ }
+ } else {
+ die "this should never happen";
+ }
+ }
+}
+
+# Select is treated a bit differently than depends. We call this
+# when a config has no prompt and requires another config to be
+# selected. We use to just select all configs that selected this
+# config, but found that that can balloon into enabling hundreds
+# of configs that we do not care about.
+#
+# The idea is we look at all the configs that select it. If one
+# is already in our list of configs to enable, then there's nothing
+# else to do. If there isn't, we pick the first config that was
+# enabled in the original config and use that.
+sub parse_config_selects
+{
+ my ($config, $p) = @_;
+
+ my $next_config;
+
+ while ($p =~ /[$valid]/) {
+
+ if ($p =~ /^[^$valid]*([$valid]+)/) {
+ my $conf = "CONFIG_" . $1;
+
+ $p =~ s/^[^$valid]*[$valid]+//;
+
+ # Make sure that this config exists in the current .config file
+ if (!defined($orig_configs{$conf})) {
+ dprint "$conf not set for $config select\n";
+ next;
+ }
+
+ # Check if something other than a module selects this config
+ if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
+ dprint "$conf (non module) selects $config, we are good\n";
+ # we are good with this
+ return;
+ }
+ if (defined($configs{$conf})) {
+ dprint "$conf selects $config so we are good\n";
+ # A set config selects this config, we are good
+ return;
+ }
+ # Set this config to be selected
+ if (!defined($next_config)) {
+ $next_config = $conf;
+ }
+ } else {
+ die "this should never happen";
+ }
+ }
+
+ # If no possible config selected this, then something happened.
+ if (!defined($next_config)) {
+
+ # Some config options have no prompt, and nothing selects them, but
+ # they stay turned on once the final checks for the configs
+ # are done. These configs have a default option, so turn off the
+ # warnings for configs with default options.
+ if (!defined($defaults{$config})) {
+ print STDERR "WARNING: $config is required, but nothing in the\n";
+ print STDERR " current config selects it.\n";
+ }
+
+ return;
+ }
+
+ # If we are here, then we found no config that is set and
+ # selects this config. Repeat.
+ $repeat = 1;
+ # Make this config need to be selected
+ $configs{$next_config} = 1;
+ dprint "$next_config selected by select $config\n";
+}
+
+my %process_selects;
+
+# loop through all configs, select their dependencies.
+sub loop_depend {
+ $repeat = 1;
+
+ while ($repeat) {
+ $repeat = 0;
+
+ forloop:
+ foreach my $config (keys %configs) {
+
+ # If this config is not a module, we do not need to process it
+ if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
+ next forloop;
+ }
+
+ $config =~ s/^CONFIG_//;
+ $depconfig = $config;
+
+ if (defined($depends{$config})) {
+ # This config has dependencies. Make sure they are also included
+ parse_config_depends $depends{$config};
+ }
+
+ # If the config has no prompt, then we need to check if a config
+ # that is enabled selected it. Or if we need to enable one.
+ if (!defined($prompts{$config}) && defined($selects{$config})) {
+ $process_selects{$config} = 1;
+ }
+ }
+ }
+}
+
+sub loop_select {
+
+ foreach my $config (keys %process_selects) {
+ $config =~ s/^CONFIG_//;
+
+ dprint "Process select $config\n";
+
+ # config has no prompt and must be selected.
+ parse_config_selects $config, $selects{$config};
+ }
+}
+
+while ($repeat) {
+ # Get the first set of configs and their dependencies.
+ loop_depend;
+
+ $repeat = 0;
+
+ # Now we need to see if we have to check selects;
+ loop_select;
+}
+
+my %setconfigs;
+my @preserved_kconfigs;
+if (defined($ENV{'LMC_KEEP'})) {
+ @preserved_kconfigs = split(/:/,$ENV{LMC_KEEP});
+}
+
+sub in_preserved_kconfigs {
+ my $kconfig = $config2kfile{$_[0]};
+ if (!defined($kconfig)) {
+ return 0;
+ }
+ foreach my $excl (@preserved_kconfigs) {
+ if($kconfig =~ /^$excl/) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+# Finally, read the .config file and turn off any module enabled that
+# we could not find a reason to keep enabled.
+foreach my $line (@config_file) {
+ $_ = $line;
+
+ if (/CONFIG_IKCONFIG/) {
+ if (/# CONFIG_IKCONFIG is not set/) {
+ # enable IKCONFIG at least as a module
+ print "CONFIG_IKCONFIG=m\n";
+ # don't ask about PROC
+ print "# CONFIG_IKCONFIG_PROC is not set\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ if (/CONFIG_MODULE_SIG_KEY="(.+)"/) {
+ my $orig_cert = $1;
+ my $default_cert = "certs/signing_key.pem";
+
+ # Check that the logic in this script still matches the one in Kconfig
+ if (!defined($depends{"MODULE_SIG_KEY"}) ||
+ $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
+ print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
+ "update needed to ", __FILE__, " line ", __LINE__, "\n";
+ print;
+ } elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
+ print STDERR "Module signature verification enabled but ",
+ "module signing key \"$orig_cert\" not found. Resetting ",
+ "signing key to default value.\n";
+ print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) {
+ my $orig_keys = $1;
+
+ if (! -f $orig_keys) {
+ print STDERR "System keyring enabled but keys \"$orig_keys\" ",
+ "not found. Resetting keys to default value.\n";
+ print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ if (/^(CONFIG.*)=(m|y)/) {
+ if (in_preserved_kconfigs($1)) {
+ dprint "Preserve config $1";
+ print;
+ next;
+ }
+ if (defined($configs{$1})) {
+ if ($localyesconfig) {
+ $setconfigs{$1} = 'y';
+ print "$1=y\n";
+ next;
+ } else {
+ $setconfigs{$1} = $2;
+ }
+ } elsif ($2 eq "m") {
+ print "# $1 is not set\n";
+ next;
+ }
+ }
+ print;
+}
+
+# Integrity check, make sure all modules that we want enabled do
+# indeed have their configs set.
+loop:
+foreach my $module (keys(%modules)) {
+ if (defined($objects{$module})) {
+ my @arr = @{$objects{$module}};
+ foreach my $conf (@arr) {
+ if (defined($setconfigs{$conf})) {
+ next loop;
+ }
+ }
+ print STDERR "module $module did not have configs";
+ foreach my $conf (@arr) {
+ print STDERR " " , $conf;
+ }
+ print STDERR "\n";
+ }
+}
+
+# vim: softtabstop=4
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
new file mode 100644
index 00000000..7e81b367
--- /dev/null
+++ b/scripts/kconfig/symbol.c
@@ -0,0 +1,1366 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+
+#include <hash.h>
+#include <xalloc.h>
+#include "internal.h"
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+ .name = "y",
+ .type = S_TRISTATE,
+ .curr = { "y", yes },
+ .menus = LIST_HEAD_INIT(symbol_yes.menus),
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+};
+
+struct symbol symbol_mod = {
+ .name = "m",
+ .type = S_TRISTATE,
+ .curr = { "m", mod },
+ .menus = LIST_HEAD_INIT(symbol_mod.menus),
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+};
+
+struct symbol symbol_no = {
+ .name = "n",
+ .type = S_TRISTATE,
+ .curr = { "n", no },
+ .menus = LIST_HEAD_INIT(symbol_no.menus),
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+};
+
+struct symbol *modules_sym;
+static tristate modules_val;
+static int sym_warnings;
+
+enum symbol_type sym_get_type(const struct symbol *sym)
+{
+ enum symbol_type type = sym->type;
+
+ if (type == S_TRISTATE && modules_val == no)
+ type = S_BOOLEAN;
+ return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+ switch (type) {
+ case S_BOOLEAN:
+ return "bool";
+ case S_TRISTATE:
+ return "tristate";
+ case S_INT:
+ return "integer";
+ case S_HEX:
+ return "hex";
+ case S_STRING:
+ return "string";
+ case S_UNKNOWN:
+ return "unknown";
+ }
+ return "???";
+}
+
+/**
+ * sym_get_prompt_menu - get the menu entry with a prompt
+ *
+ * @sym: a symbol pointer
+ *
+ * Return: the menu entry with a prompt.
+ */
+struct menu *sym_get_prompt_menu(const struct symbol *sym)
+{
+ struct menu *m;
+
+ list_for_each_entry(m, &sym->menus, link)
+ if (m->prompt)
+ return m;
+
+ return NULL;
+}
+
+/**
+ * sym_get_choice_menu - get the parent choice menu if present
+ *
+ * @sym: a symbol pointer
+ *
+ * Return: a choice menu if this function is called against a choice member.
+ */
+struct menu *sym_get_choice_menu(const struct symbol *sym)
+{
+ struct menu *menu = NULL;
+
+ /*
+ * Choice members must have a prompt. Find a menu entry with a prompt,
+ * and assume it resides inside a choice block.
+ */
+ menu = sym_get_prompt_menu(sym);
+ if (!menu)
+ return NULL;
+
+ do {
+ menu = menu->parent;
+ } while (menu && !menu->sym);
+
+ if (menu && menu->sym && sym_is_choice(menu->sym))
+ return menu;
+
+ return NULL;
+}
+
+static struct property *sym_get_default_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_RANGE) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static long long sym_get_range_val(struct symbol *sym, int base)
+{
+ sym_calc_value(sym);
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ break;
+ }
+ return strtoll(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *range_sym;
+ int base;
+ long long val, val2;
+
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ return;
+ }
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return;
+ val = strtoll(sym->curr.val, NULL, base);
+ range_sym = prop->expr->left.sym;
+ val2 = sym_get_range_val(range_sym, base);
+ if (val >= val2) {
+ range_sym = prop->expr->right.sym;
+ val2 = sym_get_range_val(range_sym, base);
+ if (val <= val2)
+ return;
+ }
+ sym->curr.val = range_sym->curr.val;
+}
+
+static void sym_set_changed(struct symbol *sym)
+{
+ struct menu *menu;
+
+ list_for_each_entry(menu, &sym->menus, link)
+ menu->flags |= MENU_CHANGED;
+
+ menu = sym_get_choice_menu(sym);
+ if (menu)
+ menu->flags |= MENU_CHANGED;
+}
+
+static void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+
+ for_all_symbols(sym)
+ sym_set_changed(sym);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+ struct property *prop;
+ tristate tri;
+
+ if (sym->flags & SYMBOL_TRANS) {
+ sym->visible = yes;
+ return;
+ }
+
+ /* any prompt visible? */
+ tri = no;
+ for_all_prompts(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ tri = EXPR_OR(tri, prop->visible.tri);
+ }
+ if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+ tri = yes;
+ if (sym->visible != tri) {
+ sym->visible = tri;
+ sym_set_changed(sym);
+ }
+ if (sym_is_choice_value(sym))
+ return;
+ /* defaulting to "yes" if no explicit "depends on" are given */
+ tri = yes;
+ if (sym->dir_dep.expr)
+ tri = expr_calc_value(sym->dir_dep.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->dir_dep.tri != tri) {
+ sym->dir_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+ tri = no;
+ if (sym->rev_dep.expr)
+ tri = expr_calc_value(sym->rev_dep.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->rev_dep.tri != tri) {
+ sym->rev_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+ tri = no;
+ if (sym->implied.expr)
+ tri = expr_calc_value(sym->implied.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->implied.tri != tri) {
+ sym->implied.tri = tri;
+ sym_set_changed(sym);
+ }
+}
+
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct menu *choice)
+{
+ struct menu *menu;
+ struct symbol *def_sym;
+ struct property *prop;
+
+ /* any of the defaults visible? */
+ for_all_defaults(choice->sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri == no)
+ continue;
+ def_sym = prop_get_symbol(prop);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* just get the first visible value */
+ menu_for_each_sub_entry(menu, choice)
+ if (menu->sym && menu->sym->visible != no)
+ return menu->sym;
+
+ /* failed to locate any defaults */
+ return NULL;
+}
+
+/*
+ * sym_calc_choice - calculate symbol values in a choice
+ *
+ * @choice: a menu of the choice
+ *
+ * Return: a chosen symbol
+ */
+struct symbol *sym_calc_choice(struct menu *choice)
+{
+ struct symbol *res = NULL;
+ struct symbol *sym;
+ struct menu *menu;
+
+ /* Traverse the list of choice members in the priority order. */
+ list_for_each_entry(sym, &choice->choice_members, choice_link) {
+ sym_calc_visibility(sym);
+ if (sym->visible == no)
+ continue;
+
+ /* The first visible symble with the user value 'y'. */
+ if (sym_has_value(sym) && sym->def[S_DEF_USER].tri == yes) {
+ res = sym;
+ break;
+ }
+ }
+
+ /*
+ * If 'y' is not found in the user input, use the default, unless it is
+ * explicitly set to 'n'.
+ */
+ if (!res) {
+ res = sym_choice_default(choice);
+ if (res && sym_has_value(res) && res->def[S_DEF_USER].tri == no)
+ res = NULL;
+ }
+
+ /* Still not found. Pick up the first visible, user-unspecified symbol. */
+ if (!res) {
+ menu_for_each_sub_entry(menu, choice) {
+ sym = menu->sym;
+
+ if (!sym || sym->visible == no || sym_has_value(sym))
+ continue;
+
+ res = sym;
+ break;
+ }
+ }
+
+ /*
+ * Still not found. Traverse the linked list in the _reverse_ order to
+ * pick up the least prioritized 'n'.
+ */
+ if (!res) {
+ list_for_each_entry_reverse(sym, &choice->choice_members,
+ choice_link) {
+ if (sym->visible == no)
+ continue;
+
+ res = sym;
+ break;
+ }
+ }
+
+ menu_for_each_sub_entry(menu, choice) {
+ tristate val;
+
+ sym = menu->sym;
+
+ if (!sym || sym->visible == no)
+ continue;
+
+ val = sym == res ? yes : no;
+
+ if (sym->curr.tri != val)
+ sym_set_changed(sym);
+
+ sym->curr.tri = val;
+ sym->flags |= SYMBOL_VALID | SYMBOL_WRITE;
+ }
+
+ return res;
+}
+
+static void sym_warn_unmet_dep(const 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);
+ str_free(&gs);
+ sym_warnings++;
+}
+
+bool sym_dep_errors(void)
+{
+ if (sym_warnings)
+ return getenv("KCONFIG_WERROR");
+ return false;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+ struct symbol_value newval, oldval;
+ struct property *prop = NULL;
+ struct menu *choice_menu;
+
+ if (!sym)
+ return;
+
+ if (sym->flags & SYMBOL_VALID)
+ return;
+
+ sym->flags |= SYMBOL_VALID;
+
+ oldval = sym->curr;
+
+ newval.tri = no;
+
+ switch (sym->type) {
+ case S_INT:
+ newval.val = "0";
+ break;
+ case S_HEX:
+ newval.val = "0x0";
+ break;
+ case S_STRING:
+ newval.val = "";
+ break;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ newval.val = "n";
+ break;
+ default:
+ sym->curr.val = sym->name;
+ sym->curr.tri = no;
+ return;
+ }
+ sym->flags &= ~SYMBOL_WRITE;
+
+ sym_calc_visibility(sym);
+
+ if (sym->visible != no)
+ sym->flags |= SYMBOL_WRITE;
+
+ /* set default if recursively called */
+ sym->curr = newval;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ choice_menu = sym_get_choice_menu(sym);
+
+ if (choice_menu) {
+ sym_calc_choice(choice_menu);
+ newval.tri = sym->curr.tri;
+ } else {
+ if (sym->visible != no) {
+ /* if the symbol is visible use the user value
+ * if available, otherwise try the default value
+ */
+ if (sym_has_value(sym)) {
+ newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+ sym->visible);
+ goto calc_newval;
+ }
+ }
+ if (sym->rev_dep.tri != no)
+ sym->flags |= SYMBOL_WRITE;
+ if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ 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;
+ newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
+ newval.tri = EXPR_AND(newval.tri,
+ sym->dir_dep.tri);
+ }
+ }
+ calc_newval:
+ 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 && sym_get_type(sym) == S_BOOLEAN)
+ newval.tri = yes;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ 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) {
+ struct symbol *ds = prop_get_symbol(prop);
+ if (ds) {
+ sym->flags |= SYMBOL_WRITE;
+ sym_calc_value(ds);
+ newval.val = ds->curr.val;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+
+ /*
+ * If the symbol lacks a user value but its value comes from a
+ * single transitional symbol with an existing user value, mark
+ * this symbol as having a user value to avoid prompting.
+ */
+ if (prop && !sym_has_value(sym)) {
+ struct symbol *ds = prop_get_symbol(prop);
+ if (ds && (ds->flags & SYMBOL_TRANS) && sym_has_value(ds)) {
+ sym->def[S_DEF_USER] = newval;
+ sym->flags |= SYMBOL_DEF_USER;
+ }
+ }
+
+ sym->curr = newval;
+ sym_validate_range(sym);
+
+ if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+ sym_set_changed(sym);
+ if (modules_sym == sym) {
+ sym_set_all_changed();
+ modules_val = modules_sym->curr.tri;
+ }
+ }
+
+ if (sym_is_choice(sym) || sym->flags & SYMBOL_TRANS)
+ sym->flags &= ~SYMBOL_WRITE;
+}
+
+void sym_clear_all_valid(void)
+{
+ struct symbol *sym;
+
+ for_all_symbols(sym)
+ sym->flags &= ~SYMBOL_VALID;
+ expr_invalidate_all();
+ conf_set_changed(true);
+ sym_calc_value(modules_sym);
+}
+
+bool sym_tristate_within_range(const struct symbol *sym, tristate val)
+{
+ int type = sym_get_type(sym);
+
+ if (sym->visible == no)
+ return false;
+
+ if (type != S_BOOLEAN && type != S_TRISTATE)
+ return false;
+
+ if (type == S_BOOLEAN && val == mod)
+ return false;
+ if (sym->visible <= sym->rev_dep.tri)
+ return false;
+ return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+ tristate oldval = sym_get_tristate_value(sym);
+
+ if (!sym_tristate_within_range(sym, val))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER) || sym->def[S_DEF_USER].tri != val) {
+ sym->def[S_DEF_USER].tri = val;
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+
+ if (oldval != val)
+ sym_clear_all_valid();
+
+ return true;
+}
+
+/**
+ * choice_set_value - set the user input to a choice
+ *
+ * @choice: menu entry for the choice
+ * @sym: selected symbol
+ */
+void choice_set_value(struct menu *choice, struct symbol *sym)
+{
+ struct menu *menu;
+ bool changed = false;
+
+ menu_for_each_sub_entry(menu, choice) {
+ tristate val;
+
+ if (!menu->sym)
+ continue;
+
+ if (menu->sym->visible == no)
+ continue;
+
+ val = menu->sym == sym ? yes : no;
+
+ if (menu->sym->curr.tri != val)
+ changed = true;
+
+ menu->sym->def[S_DEF_USER].tri = val;
+ menu->sym->flags |= SYMBOL_DEF_USER;
+
+ /*
+ * Now, the user has explicitly enabled or disabled this symbol,
+ * it should be given the highest priority. We are possibly
+ * setting multiple symbols to 'n', where the first symbol is
+ * given the least prioritized 'n'. This works well when the
+ * choice block ends up with selecting 'n' symbol.
+ * (see sym_calc_choice())
+ */
+ list_move(&menu->sym->choice_link, &choice->choice_members);
+ }
+
+ if (changed)
+ sym_clear_all_valid();
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+ struct menu *choice;
+ tristate oldval, newval;
+
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
+ choice_set_value(choice, sym);
+ return yes;
+ }
+
+ oldval = newval = sym_get_tristate_value(sym);
+ do {
+ switch (newval) {
+ case no:
+ newval = mod;
+ break;
+ case mod:
+ newval = yes;
+ break;
+ case yes:
+ newval = no;
+ break;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ break;
+ } while (oldval != newval);
+ return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+ signed char ch;
+
+ switch (sym->type) {
+ case S_STRING:
+ return true;
+ case S_INT:
+ ch = *str++;
+ if (ch == '-')
+ ch = *str++;
+ if (!isdigit(ch))
+ return false;
+ if (ch == '0' && *str != 0)
+ return false;
+ while ((ch = *str++)) {
+ if (!isdigit(ch))
+ return false;
+ }
+ return true;
+ case S_HEX:
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ str += 2;
+ ch = *str++;
+ do {
+ if (!isxdigit(ch))
+ return false;
+ } while ((ch = *str++));
+ return true;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ case 'm': case 'M':
+ case 'n': case 'N':
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+ struct property *prop;
+ long long val;
+
+ switch (sym->type) {
+ case S_STRING:
+ return sym_string_valid(sym, str);
+ case S_INT:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtoll(str, NULL, 10);
+ return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 10);
+ case S_HEX:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtoll(str, NULL, 16);
+ return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 16);
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ return sym_tristate_within_range(sym, yes);
+ case 'm': case 'M':
+ return sym_tristate_within_range(sym, mod);
+ case 'n': case 'N':
+ return sym_tristate_within_range(sym, no);
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+ const char *oldval;
+ char *val;
+ int size;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (newval[0]) {
+ case 'y': case 'Y':
+ return sym_set_tristate_value(sym, yes);
+ case 'm': case 'M':
+ return sym_set_tristate_value(sym, mod);
+ case 'n': case 'N':
+ return sym_set_tristate_value(sym, no);
+ }
+ return false;
+ default:
+ ;
+ }
+
+ if (!sym_string_within_range(sym, newval))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+
+ oldval = sym->def[S_DEF_USER].val;
+ size = strlen(newval) + 1;
+ if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+ size += 2;
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
+ *val++ = '0';
+ *val++ = 'x';
+ } else if (!oldval || strcmp(oldval, newval))
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
+ else
+ return true;
+
+ strcpy(val, newval);
+ free((void *)oldval);
+ sym_clear_all_valid();
+
+ return true;
+}
+
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *ds;
+ const char *str = "";
+ tristate val;
+
+ sym_calc_visibility(sym);
+ sym_calc_value(modules_sym);
+ val = symbol_no.curr.tri;
+
+ /* If symbol has a default value look it up */
+ prop = sym_get_default_prop(sym);
+ if (prop != NULL) {
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /* The visibility may limit the value from yes => mod */
+ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+ break;
+ default:
+ /*
+ * The following fails to handle the situation
+ * where a default value is further limited by
+ * the valid range.
+ */
+ ds = prop_get_symbol(prop);
+ if (ds != NULL) {
+ sym_calc_value(ds);
+ str = (const char *)ds->curr.val;
+ }
+ }
+ }
+
+ /* Handle select statements */
+ val = EXPR_OR(val, sym->rev_dep.tri);
+
+ /* transpose mod to yes if modules are not enabled */
+ if (val == mod)
+ if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+ val = yes;
+
+ /* transpose mod to yes if type is bool */
+ if (sym->type == S_BOOLEAN && val == mod)
+ val = yes;
+
+ /* adjust the default value if this symbol is implied by another */
+ if (val < sym->implied.tri)
+ val = sym->implied.tri;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (val) {
+ case no: return "n";
+ case mod: return "m";
+ case yes: return "y";
+ }
+ case S_INT:
+ if (!str[0])
+ str = "0";
+ break;
+ case S_HEX:
+ if (!str[0])
+ str = "0x0";
+ break;
+ default:
+ break;
+ }
+ return str;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+ tristate val;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ return "n";
+ case mod:
+ return "m";
+ case yes:
+ return "y";
+ }
+ break;
+ default:
+ ;
+ }
+ return sym->curr.val;
+}
+
+bool sym_is_changeable(const struct symbol *sym)
+{
+ return !sym_is_choice(sym) && sym->visible > sym->rev_dep.tri;
+}
+
+bool sym_is_choice_value(const struct symbol *sym)
+{
+ return !list_empty(&sym->choice_link);
+}
+
+HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE);
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+ struct symbol *symbol;
+ char *new_name;
+ int hash;
+
+ if (name) {
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = hash_str(name);
+
+ hash_for_each_possible(sym_hashtable, symbol, node, hash) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & SYMBOL_CONST)))
+ return symbol;
+ }
+ new_name = xstrdup(name);
+ } else {
+ new_name = NULL;
+ hash = 0;
+ }
+
+ symbol = xmalloc(sizeof(*symbol));
+ memset(symbol, 0, sizeof(*symbol));
+ symbol->name = new_name;
+ symbol->type = S_UNKNOWN;
+ symbol->flags = flags;
+ INIT_LIST_HEAD(&symbol->menus);
+ INIT_LIST_HEAD(&symbol->choice_link);
+
+ hash_add(sym_hashtable, &symbol->node, hash);
+
+ return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+ struct symbol *symbol = NULL;
+ int hash = 0;
+
+ if (!name)
+ return NULL;
+
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = hash_str(name);
+
+ hash_for_each_possible(sym_hashtable, symbol, node, hash) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ !(symbol->flags & SYMBOL_CONST))
+ break;
+ }
+
+ return symbol;
+}
+
+struct sym_match {
+ struct symbol *sym;
+ off_t so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp(const void *sym1, const void *sym2)
+{
+ const struct sym_match *s1 = sym1;
+ const struct sym_match *s2 = sym2;
+ int exact1, exact2;
+
+ /* Exact match:
+ * - if matched length on symbol s1 is the length of that symbol,
+ * then this symbol should come first;
+ * - if matched length on symbol s2 is the length of that symbol,
+ * then this symbol should come first.
+ * Note: since the search can be a regexp, both symbols may match
+ * exactly; if this is the case, we can't decide which comes first,
+ * and we fallback to sorting alphabetically.
+ */
+ exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+ exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+ if (exact1 && !exact2)
+ return -1;
+ if (!exact1 && exact2)
+ return 1;
+
+ /* As a fallback, sort symbols alphabetically */
+ return strcmp(s1->sym->name, s2->sym->name);
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+ struct symbol *sym, **sym_arr = NULL;
+ struct sym_match *sym_match_arr = NULL;
+ int i, cnt, size;
+ regex_t re;
+ regmatch_t match[1];
+
+ cnt = size = 0;
+ /* Skip if empty */
+ if (strlen(pattern) == 0)
+ return NULL;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
+ return NULL;
+
+ for_all_symbols(sym) {
+ if (sym->flags & SYMBOL_CONST || !sym->name)
+ continue;
+ if (regexec(&re, sym->name, 1, match, 0))
+ continue;
+ if (cnt >= size) {
+ void *tmp;
+ size += 16;
+ tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+ if (!tmp)
+ goto sym_re_search_free;
+ sym_match_arr = tmp;
+ }
+ sym_calc_value(sym);
+ /* As regexec returned 0, we know we have a match, so
+ * we can use match[0].rm_[se]o without further checks
+ */
+ sym_match_arr[cnt].so = match[0].rm_so;
+ sym_match_arr[cnt].eo = match[0].rm_eo;
+ sym_match_arr[cnt++].sym = sym;
+ }
+ if (sym_match_arr) {
+ qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
+ sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
+ if (!sym_arr)
+ goto sym_re_search_free;
+ for (i = 0; i < cnt; i++)
+ sym_arr[i] = sym_match_arr[i].sym;
+ sym_arr[cnt] = NULL;
+ }
+sym_re_search_free:
+ /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+ free(sym_match_arr);
+ regfree(&re);
+
+ return sym_arr;
+}
+
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note insert() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+ struct dep_stack *prev, *next;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr **expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+ memset(stack, 0, sizeof(*stack));
+ if (check_top)
+ check_top->next = stack;
+ stack->prev = check_top;
+ stack->sym = sym;
+ check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+ check_top = check_top->prev;
+ if (check_top)
+ check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+ struct dep_stack *stack;
+ struct symbol *sym, *next_sym;
+ struct menu *choice;
+ struct dep_stack cv_stack;
+ enum prop_type type;
+
+ choice = sym_get_choice_menu(last_sym);
+ if (choice) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = choice->sym;
+ }
+
+ for (stack = check_top; stack != NULL; stack = stack->prev)
+ if (stack->sym == last_sym)
+ break;
+ if (!stack) {
+ fprintf(stderr, "unexpected recursive dependency error\n");
+ return;
+ }
+
+ for (; stack; stack = stack->next) {
+ sym = stack->sym;
+ next_sym = stack->next ? stack->next->sym : last_sym;
+ type = stack->prop ? stack->prop->type : P_UNKNOWN;
+
+ if (stack->sym == last_sym)
+ fprintf(stderr, "error: recursive dependency detected!\n");
+
+ if (sym_is_choice(next_sym)) {
+ choice = list_first_entry(&next_sym->menus, struct menu, link);
+
+ fprintf(stderr, "\tsymbol %s is part of choice block at %s:%d\n",
+ sym->name ? sym->name : "<choice>",
+ choice->filename, choice->lineno);
+ } else if (stack->expr == &sym->dir_dep.expr) {
+ fprintf(stderr, "\tsymbol %s depends on %s\n",
+ sym->name ? sym->name : "<choice>",
+ next_sym->name);
+ } else if (stack->expr == &sym->rev_dep.expr) {
+ fprintf(stderr, "\tsymbol %s is selected by %s\n",
+ sym->name, next_sym->name);
+ } else if (stack->expr == &sym->implied.expr) {
+ fprintf(stderr, "\tsymbol %s is implied by %s\n",
+ sym->name, next_sym->name);
+ } else if (stack->expr) {
+ fprintf(stderr, "\tsymbol %s %s value contains %s\n",
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(type),
+ next_sym->name);
+ } else {
+ fprintf(stderr, "\tsymbol %s %s is visible depending on %s\n",
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(type),
+ next_sym->name);
+ }
+ }
+
+ fprintf(stderr,
+ "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n"
+ "subsection \"Kconfig recursive dependency limitations\"\n"
+ "\n");
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(const struct expr *e)
+{
+ struct symbol *sym;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_OR:
+ case E_AND:
+ sym = sym_check_expr_deps(e->left.expr);
+ if (sym)
+ return sym;
+ return sym_check_expr_deps(e->right.expr);
+ case E_NOT:
+ return sym_check_expr_deps(e->left.expr);
+ case E_EQUAL:
+ case E_GEQ:
+ case E_GTH:
+ case E_LEQ:
+ case E_LTH:
+ case E_UNEQUAL:
+ sym = sym_check_deps(e->left.sym);
+ if (sym)
+ return sym;
+ return sym_check_deps(e->right.sym);
+ case E_SYMBOL:
+ return sym_check_deps(e->left.sym);
+ default:
+ break;
+ }
+ fprintf(stderr, "Oops! How to check %d?\n", e->type);
+ return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+ struct dep_stack stack;
+
+ 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_SELECT || prop->type == P_IMPLY)
+ continue;
+ stack.prop = prop;
+ sym2 = sym_check_expr_deps(prop->visible.expr);
+ if (sym2)
+ break;
+ if (prop->type != P_DEFAULT || sym_is_choice(sym))
+ continue;
+ stack.expr = &prop->expr;
+ sym2 = sym_check_expr_deps(prop->expr);
+ if (sym2)
+ break;
+ stack.expr = NULL;
+ }
+
+out:
+ dep_stack_remove();
+
+ return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+ struct menu *choice_menu, *menu;
+ struct symbol *sym2;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
+
+ choice_menu = list_first_entry(&choice->menus, struct menu, link);
+
+ menu_for_each_sub_entry(menu, choice_menu) {
+ if (menu->sym)
+ menu->sym->flags |= SYMBOL_CHECK | SYMBOL_CHECKED;
+ }
+
+ choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(choice);
+ choice->flags &= ~SYMBOL_CHECK;
+ if (sym2)
+ goto out;
+
+ menu_for_each_sub_entry(menu, choice_menu) {
+ if (!menu->sym)
+ continue;
+ sym2 = sym_check_sym_deps(menu->sym);
+ if (sym2)
+ break;
+ }
+out:
+ menu_for_each_sub_entry(menu, choice_menu)
+ if (menu->sym)
+ menu->sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2) {
+ struct menu *choice_menu2;
+
+ choice_menu2 = sym_get_choice_menu(sym2);
+ if (choice_menu2 == choice_menu)
+ sym2 = choice;
+ }
+
+ dep_stack_remove();
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct menu *choice;
+ struct symbol *sym2;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ sym_check_print_recursive(sym);
+ return sym;
+ }
+ if (sym->flags & SYMBOL_CHECKED)
+ return NULL;
+
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
+ struct dep_stack stack;
+
+ /* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
+ sym2 = sym_check_deps(choice->sym);
+ dep_stack_remove();
+ } else if (sym_is_choice(sym)) {
+ sym2 = sym_check_choice_deps(sym);
+ } else {
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(sym);
+ sym->flags &= ~SYMBOL_CHECK;
+ }
+
+ return sym2;
+}
+
+struct symbol *prop_get_symbol(const struct property *prop)
+{
+ if (prop->expr && prop->expr->type == E_SYMBOL)
+ return prop->expr->left.sym;
+ return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+ switch (type) {
+ case P_PROMPT:
+ return "prompt";
+ case P_COMMENT:
+ return "comment";
+ case P_MENU:
+ return "menu";
+ case P_DEFAULT:
+ return "default";
+ case P_SELECT:
+ return "select";
+ case P_IMPLY:
+ return "imply";
+ case P_RANGE:
+ return "range";
+ case P_UNKNOWN:
+ break;
+ }
+ return "unknown";
+}
diff --git a/scripts/kconfig/textbox.c b/scripts/kconfig/textbox.c
new file mode 100644
index 00000000..0abaf635
--- /dev/null
+++ b/scripts/kconfig/textbox.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * textbox.c -- implements the text box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ */
+
+#include "dialog.h"
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf, *page;
+static size_t start, end;
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+ int i;
+
+ begin_reached = 0;
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++) {
+ if (*page == '\0') {
+ if (end_reached) {
+ end_reached = 0;
+ continue;
+ }
+ }
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ do {
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ } while (*page != '\n');
+ page++;
+ }
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+ int i = 0;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+ end_reached = 1;
+ break;
+ } else if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ /* Truncate lines longer than MAX_LEN characters */
+ if (i == MAX_LEN)
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move past '\n' */
+
+ return line;
+}
+
+/*
+ * Print a new line of text.
+ */
+static void print_line(WINDOW *win, int row, int width)
+{
+ char *line;
+
+ line = get_line();
+ line += MIN(strlen(line), hscroll); /* Scroll horizontally */
+ wmove(win, row, 0); /* move cursor to correct line */
+ waddch(win, ' ');
+ waddnstr(win, line, MIN(strlen(line), width - 2));
+
+ /* Clear 'residue' of previous line */
+ wclrtoeol(win);
+}
+
+/*
+ * Print a new page of text.
+ */
+static void print_page(WINDOW *win, int height, int width)
+{
+ int i, passed_end = 0;
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line(win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh(win);
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW *win)
+{
+ int percent;
+
+ wattrset(win, dlg.position_indicator.atr);
+ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+ percent = (page - buf) * 100 / strlen(buf);
+ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+ wprintw(win, "(%3d%%)", percent);
+}
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+ int cur_y, int cur_x)
+{
+ start = page - buf;
+
+ print_page(box, boxh, boxw);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+
+ end = page - buf;
+}
+
+/*
+ * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ */
+int dialog_textbox(const char *title, const char *tbuf, int initial_height,
+ int initial_width, int *_vscroll, int *_hscroll,
+ int (*extra_key_cb)(int, size_t, size_t, void *), void *data)
+{
+ int i, x, y, cur_x, cur_y, key = 0;
+ int height, width, boxh, boxw;
+ WINDOW *dialog, *box;
+ bool done = false;
+
+ begin_reached = 1;
+ end_reached = 0;
+ page_length = 0;
+ hscroll = 0;
+ buf = tbuf;
+ page = buf; /* page is pointer to start of page to be displayed */
+
+ if (_vscroll && *_vscroll) {
+ begin_reached = 0;
+
+ for (i = 0; i < *_vscroll; i++)
+ get_line();
+ }
+ if (_hscroll)
+ hscroll = *_hscroll;
+
+do_resize:
+ getmaxyx(stdscr, height, width);
+ if (height < TEXTBOX_HEIGHT_MIN || width < TEXTBOX_WIDTH_MIN)
+ return -ERRDISPLAYTOOSMALL;
+ if (initial_height != 0)
+ height = initial_height;
+ else
+ if (height > 4)
+ height -= 4;
+ else
+ height = 0;
+ if (initial_width != 0)
+ width = initial_width;
+ else
+ if (width > 5)
+ width -= 5;
+ else
+ width = 0;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ /* Create window for box region, used for scrolling text */
+ boxh = height - 4;
+ boxw = width - 2;
+ box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+ wattrset(box, dlg.dialog.atr);
+ wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+ keypad(box, TRUE);
+
+ /* register the new window, along with its borders */
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+ wnoutrefresh(dialog);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+ attr_clear(box, boxh, boxw, dlg.dialog.atr);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+ while (!done) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
+ case 'q':
+ case '\n':
+ done = true;
+ break;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+ page = buf;
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ }
+ break;
+ case 'G': /* Last page */
+ case KEY_END:
+
+ end_reached = 1;
+ /* point to last char in buf */
+ page = buf + strlen(buf);
+ back_lines(boxh);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+ case KEY_UP:
+ if (begin_reached)
+ break;
+
+ back_lines(page_length + 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ case 'u':
+ case KEY_PPAGE:
+ if (begin_reached)
+ break;
+ back_lines(page_length + boxh);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case KEY_DOWN:
+ if (end_reached)
+ break;
+
+ back_lines(page_length - 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case KEY_NPAGE: /* Next page */
+ case ' ':
+ case 'd':
+ if (end_reached)
+ break;
+
+ begin_reached = 0;
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+ case 'h':
+ case KEY_LEFT:
+ if (hscroll <= 0)
+ break;
+
+ if (key == '0')
+ hscroll = 0;
+ else
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+ case KEY_RIGHT:
+ if (hscroll >= MAX_LEN)
+ break;
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ break;
+ case KEY_ESC:
+ if (on_key_esc(dialog) == KEY_ESC)
+ done = true;
+ break;
+ case KEY_RESIZE:
+ back_lines(height);
+ delwin(box);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ default:
+ if (extra_key_cb && extra_key_cb(key, start, end, data)) {
+ done = true;
+ break;
+ }
+ }
+ }
+ delwin(box);
+ delwin(dialog);
+ if (_vscroll) {
+ const char *s;
+
+ s = buf;
+ *_vscroll = 0;
+ back_lines(page_length);
+ while (s < page && (s = strchr(s, '\n'))) {
+ (*_vscroll)++;
+ s++;
+ }
+ }
+ if (_hscroll)
+ *_hscroll = hscroll;
+ return key;
+}
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
new file mode 100644
index 00000000..5cdcee14
--- /dev/null
+++ b/scripts/kconfig/util.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hash.h>
+#include <hashtable.h>
+#include <xalloc.h>
+#include "lkc.h"
+
+/* hash table of all parsed Kconfig files */
+static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
+
+struct file {
+ struct hlist_node node;
+ char name[];
+};
+
+/* file already present in list? If not add it */
+const char *file_lookup(const char *name)
+{
+ struct file *file;
+ size_t len;
+ int hash = hash_str(name);
+
+ hash_for_each_possible(file_hashtable, file, node, hash)
+ if (!strcmp(name, file->name))
+ return file->name;
+
+ len = strlen(name);
+ file = xmalloc(sizeof(*file) + len + 1);
+ memset(file, 0, sizeof(*file));
+ memcpy(file->name, name, len);
+ file->name[len] = '\0';
+
+ hash_add(file_hashtable, &file->node, hash);
+
+ str_printf(&autoconf_cmd, "\t%s \\\n", name);
+
+ return file->name;
+}
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+ struct gstr gs;
+ gs.s = xmalloc(sizeof(char) * 64);
+ gs.len = 64;
+ gs.max_width = 0;
+ strcpy(gs.s, "\0");
+ return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+ free(gs->s);
+ gs->s = NULL;
+ gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+ size_t l;
+ if (s) {
+ l = strlen(gs->s) + strlen(s) + 1;
+ if (l > gs->len) {
+ gs->s = xrealloc(gs->s, l);
+ gs->len = l;
+ }
+ strcat(gs->s, s);
+ }
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+ va_list ap;
+ char s[10000]; /* big enough... */
+ va_start(ap, fmt);
+ vsnprintf(s, sizeof(s), fmt, ap);
+ str_append(gs, s);
+ va_end(ap);
+}
+
+/* Retrieve value of growable string */
+char *str_get(const struct gstr *gs)
+{
+ return gs->s;
+}
diff --git a/scripts/kconfig/yesno.c b/scripts/kconfig/yesno.c
new file mode 100644
index 00000000..b57d25e1
--- /dev/null
+++ b/scripts/kconfig/yesno.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * yesno.c -- implements the yes/no box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 10;
+ int y = height - 2;
+
+ print_button(dialog, " Yes ", y, x, selected == 0);
+ print_button(dialog, " No ", y, x + 13, selected == 1);
+
+ wmove(dialog, y, x + 1 + 13 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+ int i, x, y, key = 0, button = 0;
+ WINDOW *dialog;
+
+do_resize:
+ if (getmaxy(stdscr) < (height + YESNO_HEIGHT_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ print_buttons(dialog, height, width, 0);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'Y':
+ case 'y':
+ delwin(dialog);
+ return 0;
+ case 'N':
+ case 'n':
+ delwin(dialog);
+ return 1;
+
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return button;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return key; /* ESC pressed */
+}