frontends/mconf/mconf
frontends/nconf/nconf
-parser/?conf.c
+libs/parser/?conf.c
aclocal.m4
configure
Makefile
Makefile.in
-lxdialog/Makefile
-lxdialog/Makefile.in
stamp-h1
.deps/
-SUBDIRS = lxdialog parser frontends
+SUBDIRS = libs frontends
# Finalise
AC_CONFIG_FILES([
Makefile
- lxdialog/Makefile
- parser/Makefile
+ libs/Makefile
+ libs/lxdialog/Makefile
+ libs/parser/Makefile
frontends/Makefile
frontends/conf/Makefile
frontends/mconf/Makefile
conf_SOURCES = conf.c
conf_CPPFLAGS = $(AM_CPPFLAGS) \
$(GETTEXT) \
- -I../../parser
-conf_LDADD = ../../parser/libkconfigparser.a
+ -I../../libs/parser
+conf_LDADD = ../../libs/parser/libkconfigparser.a
gconf_SOURCES = gconf.c gconf.glade
dist_EXTRA_gconf_SOURCES = images.c
-gconf_CPPFLAGS = $(AM_CPPFLAGS) \
- $(GETTEXT) \
- -I../../parser \
+gconf_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(GETTEXT) \
+ -I../../libs/parser \
-DGUI_PATH='"$(pkgdatadir)/gconf.glade"'
gconf_CFLAGS = $(AM_CFLAGS) \
$(gtk_CFLAGS)
-gconf_LDADD = $(gtk_LIBS) \
- ../../parser/libkconfigparser.a
+gconf_LDADD = $(gtk_LIBS) \
+ ../../libs/parser/libkconfigparser.a
gconfdir = $(pkgdatadir)
gconf_DATA = gconf.glade
mconf_CPPFLAGS = $(AM_CPPFLAGS) \
-DCURSES_LOC='"${CURSES_LOC}"' \
$(GETTEXT) \
- -I../../parser
-mconf_LDADD = ../../parser/libkconfigparser.a ../../lxdialog/liblxdialog.a
+ -I../../libs \
+ -I../../libs/parser
+mconf_LDADD = ../../libs/parser/libkconfigparser.a \
+ ../../libs/lxdialog/liblxdialog.a
bin_PROGRAMS = nconf
nconf_SOURCES = nconf.c nconf.gui.c nconf.h
-nconf_CPPFLAGS = $(AM_CPPFLAGS) \
- $(GETTEXT) \
- -I../../parser
-nconf_LDADD = ../../parser/libkconfigparser.a -lmenu -lpanel
+nconf_CPPFLAGS = $(AM_CPPFLAGS) \
+ $(GETTEXT) \
+ -I../../libs/parser
+nconf_LDADD = -lmenu -lpanel \
+ ../../libs/parser/libkconfigparser.a
--- /dev/null
+SUBDIRS = parser lxdialog
--- /dev/null
+#
+# Generated files
+#
+lxdialog
--- /dev/null
+This is NOT the official version of dialog. This version has been
+significantly modified from the original. It is for use by the Linux
+kernel configuration script. Please do not bother Savio Lam with
+questions about this program.
--- /dev/null
+noinst_LIBRARIES = liblxdialog.a
+
+liblxdialog_a_SOURCES = \
+ checklist.c \
+ dialog.h \
+ inputbox.c \
+ menubox.c \
+ textbox.c \
+ util.c \
+ yesno.c
+
+liblxdialog_a_CPPFLAGS = $(AM_CPPFLAGS) \
+ -DCURSES_LOC='"${CURSES_LOC}"' \
+ $(GETTEXT)
--- /dev/null
+/*
+ * 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)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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, gettext("Select"), y, x, selected == 0);
+ print_button(dialog, gettext(" 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 + 6))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 6))
+ return -ERRDISPLAYTOOSMALL;
+
+ max_choice = MIN(list_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - 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);
+
+ wnoutrefresh(dialog);
+ wnoutrefresh(list);
+ doupdate();
+
+ 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 */
+}
--- /dev/null
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked. This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses. The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef wbkgdset
+#define wbkgdset(w,p) /*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#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 dialog_info {
+ const char *backtitle;
+ 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 inputbox_border;
+ struct dialog_color searchbox;
+ struct dialog_color searchbox_title;
+ struct dialog_color searchbox_border;
+ 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[];
+
+/*
+ * 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]; /* promtp 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);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+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 *file, int height, int width);
+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);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+ int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ * -- the first 32 are used as numbers, in addition to '0'-'9'
+ * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
--- /dev/null
+/*
+ * 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)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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, gettext(" Ok "), y, x, selected == 0);
+ print_button(dialog, gettext(" 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, scroll = 0, key = 0, button = -1;
+ char *instr = dialog_input_result;
+ WINDOW *dialog;
+
+ if (!init)
+ instr[0] = '\0';
+ else
+ strcpy(instr, init);
+
+do_resize:
+ if (getmaxy(stdscr) <= (height - 2))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) <= (width - 2))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - 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);
+
+ input_x = strlen(instr);
+
+ if (input_x >= box_width) {
+ scroll = input_x - box_width + 1;
+ input_x = box_width - 1;
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr[scroll + i]);
+ } else {
+ 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_LEFT:
+ continue;
+ case KEY_RIGHT:
+ continue;
+ case KEY_BACKSPACE:
+ case 127:
+ if (input_x || scroll) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (!input_x) {
+ scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++)
+ waddch(dialog,
+ instr[scroll + input_x + i] ?
+ instr[scroll + input_x + i] : ' ');
+ input_x = strlen(instr) - scroll;
+ } else
+ input_x--;
+ instr[scroll + input_x] = '\0';
+ mvwaddch(dialog, box_y, input_x + box_x, ' ');
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ }
+ continue;
+ default:
+ if (key < 0x100 && isprint(key)) {
+ if (scroll + input_x < MAX_LEN) {
+ wattrset(dialog, dlg.inputbox.atr);
+ instr[scroll + input_x] = key;
+ instr[scroll + input_x + 1] = '\0';
+ if (input_x == box_width - 1) {
+ scroll++;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr [scroll + i]);
+ } else {
+ wmove(dialog, box_y, input_x++ + box_x);
+ waddch(dialog, key);
+ }
+ 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 */
+}
--- /dev/null
+/*
+ * 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)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * 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);
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+ 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 - 16;
+ int y = height - 2;
+
+ print_button(win, gettext("Select"), y, x, selected == 0);
+ print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+ print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+
+ 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 < 15 || width < 65)
+ return -ERRDISPLAYTOOSMALL;
+
+ height -= 4;
+ width -= 5;
+ menu_height = height - 10;
+
+ max_choice = MIN(menu_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - 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 (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)
+ ? 2 : (button > 2 ? 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 3;
+ case 'n':
+ return 4;
+ case 'm':
+ return 5;
+ case ' ':
+ return 6;
+ case '/':
+ return 7;
+ case 'z':
+ return 8;
+ 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 */
+}
--- /dev/null
+/*
+ * 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)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+ int cur_y, int cur_x)
+{
+ print_page(box, boxh, boxw);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+ int initial_height, int initial_width)
+{
+ int i, x, y, cur_x, cur_y, key = 0;
+ int height, width, boxh, boxw;
+ int passed_end;
+ WINDOW *dialog, *box;
+
+ 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 */
+
+do_resize:
+ getmaxyx(stdscr, height, width);
+ if (height < 8 || width < 8)
+ 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 = (COLS - width) / 2;
+ y = (LINES - 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, gettext(" 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 ((key != KEY_ESC) && (key != '\n')) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
+ delwin(box);
+ delwin(dialog);
+ return 0;
+ 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) {
+ back_lines(page_length + 1);
+
+ /* We don't call print_page() here but use
+ * scrolling to ensure faster screen update.
+ * However, 'end_reached' and 'page_length'
+ * should still be updated, and 'page' should
+ * point to start of next page. This is done
+ * by calling get_line() in the following
+ * 'for' loop. */
+ scrollok(box, TRUE);
+ wscrl(box, -1); /* Scroll box region down one line */
+ scrollok(box, FALSE);
+ page_length = 0;
+ passed_end = 0;
+ for (i = 0; i < boxh; i++) {
+ if (!i) {
+ /* print first line of page */
+ print_line(box, 0, boxw);
+ wnoutrefresh(box);
+ } else
+ /* Called to update 'end_reached' and 'page' */
+ get_line();
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ 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) {
+ begin_reached = 0;
+ scrollok(box, TRUE);
+ scroll(box); /* Scroll box region up one line */
+ scrollok(box, FALSE);
+ print_line(box, boxh - 1, boxw);
+ wnoutrefresh(box);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case KEY_NPAGE: /* Next page */
+ case ' ':
+ 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:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ back_lines(height);
+ delwin(box);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+ delwin(box);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
+
+/*
+ * 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++;
+ }
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+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 a new line of text. Called by dialog_textbox() and print_page().
+ */
+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 */
+#if OLD_NCURSES
+ {
+ int x = getcurx(win);
+ int i;
+ for (i = 0; i < width - x; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+}
+
+/*
+ * 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') {
+ if (!end_reached) {
+ 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 pass '\n' */
+
+ return line;
+}
+
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * util.c
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+ dlg.screen.atr = A_NORMAL;
+ dlg.shadow.atr = A_NORMAL;
+ dlg.dialog.atr = A_NORMAL;
+ dlg.title.atr = A_BOLD;
+ dlg.border.atr = A_NORMAL;
+ 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.button_label_inactive.atr = A_NORMAL;
+ dlg.inputbox.atr = A_NORMAL;
+ dlg.inputbox_border.atr = A_NORMAL;
+ dlg.searchbox.atr = A_NORMAL;
+ dlg.searchbox_title.atr = A_BOLD;
+ dlg.searchbox_border.atr = A_NORMAL;
+ dlg.position_indicator.atr = A_BOLD;
+ dlg.menubox.atr = A_NORMAL;
+ dlg.menubox_border.atr = A_NORMAL;
+ dlg.item.atr = A_NORMAL;
+ 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(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
+ 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_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
+
+ DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
+ DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ 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(searchbox_title, COLOR_BLUE, COLOR_WHITE, 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.inputbox_border);
+ init_one_color(&dlg.searchbox);
+ init_one_color(&dlg.searchbox_title);
+ init_one_color(&dlg.searchbox_border);
+ 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)
+{
+ attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+ /* Display background title if it exists ... - SLH */
+ if (dlg.backtitle != NULL) {
+ int i;
+
+ wattrset(stdscr, dlg.screen.atr);
+ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+ wmove(stdscr, 1, 1);
+ for (i = 1; i < COLS - 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 */
+ getmaxyx(stdscr, height, width);
+ if (height < 19 || width < 80) {
+ 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;
+}
+
+/*
+ * 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 replaced by spaces. 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 i, prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+ strcpy(tempstr, prompt);
+
+ prompt_len = strlen(tempstr);
+
+ /*
+ * Remove newlines
+ */
+ for (i = 0; i < prompt_len; i++) {
+ if (tempstr[i] == '\n')
+ tempstr[i] = ' ';
+ }
+
+ 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 = strchr(word, ' ');
+ 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 = strchr(sp, ' '))
+ || 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);
+ 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 thats
+ * 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);
+}
--- /dev/null
+/*
+ * 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)
+ *
+ * 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
+ * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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, gettext(" Yes "), y, x, selected == 0);
+ print_button(dialog, gettext(" 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 + 4))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 4))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - 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 */
+}
--- /dev/null
+SUFFIXES = .gperf
+
+noinst_LIBRARIES = libkconfigparser.a
+
+libkconfigparser_a_SOURCES = yconf.y
+dist_EXTRA_libkconfigparser_a_SOURCES = \
+ hconf.gperf lconf.l \
+ confdata.c menu.c symbol.c util.c \
+ expr.c expr.h lkc.h lkc_proto.h
+
+BUILT_SOURCES = hconf.c lconf.c
+
+# Can't use libkconfigparser_a_CPPFLAGS, as it breaks dependencies
+yconf.o: CPPFLAGS+=$(GETTEXT)
+
+.gperf.c:
+ $(GPERF) -t --output-file $@ -a -C -E -g -k 1,3,$$ -p -t $<
+
+# The following rule produces a warning:
+# parser/Makefile.am:31: user target `.l.c' defined here...
+# /usr/share/automake-1.11/am/lex.am: ... overrides Automake target
+# `.l.c' defined here
+#
+# This is expected, and can't be avoided (for now).
+# That's because, when working with lex+yacc sources, the default is to
+# build each files searately, and then link them together into the final
+# output. But the Linux kernel's parser simply #include-s the lexer,
+# so we can't put lconf.l into the _SOURCES (it's in EXTRA_SOURCES),
+# and thus automake does not catch the need to call lex.
+# Secondly, when flex is told to change the symbols' prefix (kconfig
+# uses zconf in lieue of the original yy), then the output file is
+# also renamed, but automake does not now that, and make would fail
+# because it would think no file was generated.
+.l.c:
+ $(LEXCOMPILE) -o$@ $<
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+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, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+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 *fmt, va_list ap)
+{
+ printf("#\n# ");
+ vprintf(fmt, ap);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (conf_message_callback)
+ conf_message_callback(fmt, ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+ struct symbol *sym;
+ const char *src;
+ static char res_value[SYMBOL_MAXLENGTH];
+ char *dst, name[SYMBOL_MAXLENGTH];
+
+ res_value[0] = 0;
+ dst = name;
+ while ((src = strchr(in, '$'))) {
+ strncat(res_value, in, src - in);
+ src++;
+ dst = name;
+ while (isalnum(*src) || *src == '_')
+ *dst++ = *src++;
+ *dst = 0;
+ sym = sym_lookup(name, 0);
+ sym_calc_value(sym);
+ strcat(res_value, sym_get_string_value(sym));
+ in = src;
+ }
+ strcat(res_value, in);
+
+ return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+ struct stat buf;
+ static char fullname[PATH_MAX+1];
+ char *env, *name;
+
+ name = conf_expand_value(conf_defname);
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ if (!stat(fullname, &buf))
+ return fullname;
+ }
+ return name;
+}
+
+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;
+ }
+ conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+ return 1;
+ case S_OTHER:
+ if (*p != '"') {
+ for (p2 = p; *p2 && !isspace(*p2); p2++)
+ ;
+ sym->type = S_STRING;
+ goto done;
+ }
+ /* fall through */
+ case S_STRING:
+ if (*p++ != '"')
+ break;
+ 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:
+ done:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = strdup(p);
+ sym->flags |= def_flags;
+ } else {
+ conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char line[1024];
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ struct property *prop;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ sym_add_change_count(1);
+ if (!sym_defconfig_list) {
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ for_all_defaults(sym_defconfig_list, prop) {
+ if (expr_calc_value(prop->visible.expr) == no ||
+ prop->expr->type != E_SYMBOL)
+ continue;
+ name = conf_expand_value(prop->expr->left.sym->name);
+ in = zconf_fopen(name);
+ if (in) {
+ conf_message(_("using defaults found in %s"),
+ name);
+ goto load;
+ }
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+ conf_unsaved = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (fgets(line, sizeof(line), in)) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_OTHER;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data");
+ continue;
+ }
+setsym:
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ fclose(in);
+
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym, *choice_sym;
+ struct property *prop;
+ struct expr *e;
+ int i, flags;
+
+ sym_set_change_count(0);
+
+ if (conf_read_simple(name, S_DEF_USER))
+ return 1;
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+ goto sym_ok;
+ 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))
+ break;
+ if (!sym_is_choice(sym))
+ goto sym_ok;
+ /* fall through */
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ goto sym_ok;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ goto sym_ok;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ sym_ok:
+ if (!sym_is_choice(sym))
+ continue;
+ /* The choice symbol only has a set value (and thus is not new)
+ * if all its visible childs have values.
+ */
+ prop = sym_get_choice_prop(sym);
+ flags = sym->flags;
+ expr_list_for_each_sym(prop->expr, e, choice_sym)
+ if (choice_sym->visible != no)
+ flags &= choice_sym->flags;
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ sym_add_change_count(conf_warnings || conf_unsaved);
+
+ return 0;
+}
+
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (*value == 'n') {
+ bool skip_unset = (arg != NULL);
+
+ if (!skip_unset)
+ fprintf(fp, "# %s%s is not set\n",
+ CONFIG_, sym->name);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, "#");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+}
+
+static struct conf_printer kconfig_printer_cb =
+{
+ .print_symbol = kconfig_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE: {
+ const char *suffix = "";
+
+ switch (*value) {
+ case 'n':
+ break;
+ case 'm':
+ suffix = "_MODULE";
+ /* fall through */
+ default:
+ fprintf(fp, "#define %s%s%s 1\n",
+ CONFIG_, sym->name, suffix);
+ }
+ break;
+ }
+ case S_HEX: {
+ const char *prefix = "";
+
+ if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+ prefix = "0x";
+ fprintf(fp, "#define %s%s %s%s\n",
+ CONFIG_, sym->name, prefix, value);
+ break;
+ }
+ case S_STRING:
+ case S_INT:
+ fprintf(fp, "#define %s%s %s\n",
+ CONFIG_, sym->name, value);
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ fprintf(fp, "/*\n");
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, " *");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+ fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+ .print_symbol = header_print_symbol,
+ .print_comment = header_print_comment,
+};
+
+/*
+ * Generate the __enabled_CONFIG_* and __enabled_CONFIG_*_MODULE macros for
+ * use by the IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is
+ * generated even for booleans so that the IS_ENABLED() macro works.
+ */
+static void
+header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE: {
+ fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n",
+ sym->name, (*value == 'y'));
+ fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n",
+ sym->name, (*value == 'm'));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static struct conf_printer header__enabled_printer_cb =
+{
+ .print_symbol = header_print__enabled_symbol,
+ .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ if (sym->type == S_TRISTATE && *value != 'n')
+ fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+ .print_symbol = tristate_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+ struct conf_printer *printer, void *printer_arg)
+{
+ const char *str;
+
+ switch (sym->type) {
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ case S_STRING:
+ str = sym_get_string_value(sym);
+ str = sym_escape_string_value(str);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ free((void *)str);
+ break;
+ default:
+ str = sym_get_string_value(sym);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ }
+}
+
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "\n"
+ "Automatically generated file; DO NOT EDIT.\n"
+ "%s\n",
+ rootmenu.prompt->text);
+
+ printer->print_comment(fp, buf, printer_arg);
+}
+
+/*
+ * 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();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *basename;
+ const char *str;
+ char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+ char *env;
+
+ dirname[0] = 0;
+ if (name && name[0]) {
+ struct stat st;
+ char *slash;
+
+ if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+ strcpy(dirname, name);
+ strcat(dirname, "/");
+ basename = conf_get_configname();
+ } else if ((slash = strrchr(name, '/'))) {
+ int size = slash - name + 1;
+ memcpy(dirname, name, size);
+ dirname[size] = 0;
+ if (slash[1])
+ basename = slash + 1;
+ else
+ basename = conf_get_configname();
+ } else
+ basename = name;
+ } else
+ basename = conf_get_configname();
+
+ sprintf(newname, "%s%s", dirname, basename);
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (!env || !*env) {
+ sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+ out = fopen(tmpname, "w");
+ } else {
+ *tmpname = 0;
+ out = fopen(newname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ 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);
+ } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ sym->flags &= ~SYMBOL_WRITE;
+
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+ if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ fclose(out);
+
+ if (*tmpname) {
+ strcat(dirname, basename);
+ strcat(dirname, ".old");
+ rename(newname, dirname);
+ if (rename(tmpname, newname))
+ return 1;
+ }
+
+ conf_message(_("configuration written to %s"), newname);
+
+ sym_set_change_count(0);
+
+ return 0;
+}
+
+static int conf_split_config(void)
+{
+ const char *name;
+ char path[PATH_MAX+1];
+ char *s, *d, c;
+ struct symbol *sym;
+ struct stat sb;
+ int res, i, fd;
+
+ name = conf_get_autoconfig_name();
+ conf_read_simple(name, S_DEF_AUTO);
+
+ if (chdir("include/config"))
+ return 1;
+
+ res = 0;
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+ 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').
+ */
+
+ /* Replace all '_' and append ".h" */
+ s = sym->name;
+ d = path;
+ while ((c = *s++)) {
+ c = tolower(c);
+ *d++ = (c == '_') ? '/' : c;
+ }
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ res = 1;
+ break;
+ }
+ /*
+ * Create directory components,
+ * unless they exist already.
+ */
+ d = path;
+ while ((d = strchr(d, '/'))) {
+ *d = 0;
+ if (stat(path, &sb) && mkdir(path, 0755)) {
+ res = 1;
+ goto out;
+ }
+ *d++ = '/';
+ }
+ /* Try it again. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ res = 1;
+ break;
+ }
+ }
+ close(fd);
+ }
+out:
+ if (chdir("../.."))
+ return 1;
+
+ return res;
+}
+
+int conf_write_autoconf(void)
+{
+ struct symbol *sym;
+ const char *name;
+ FILE *out, *tristate, *out_h;
+ int i;
+
+ sym_clear_all_valid();
+
+ file_write_dep("include/config/auto.conf.cmd");
+
+ if (conf_split_config())
+ return 1;
+
+ out = fopen(".tmpconfig", "w");
+ if (!out)
+ return 1;
+
+ tristate = fopen(".tmpconfig_tristate", "w");
+ if (!tristate) {
+ fclose(out);
+ return 1;
+ }
+
+ out_h = fopen(".tmpconfig.h", "w");
+ if (!out_h) {
+ fclose(out);
+ fclose(tristate);
+ return 1;
+ }
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+ conf_write_heading(out_h, &header_printer_cb, NULL);
+
+ for_all_symbols(i, sym) {
+ if (!sym->name)
+ continue;
+
+ sym_calc_value(sym);
+
+ conf_write_symbol(out_h, sym, &header__enabled_printer_cb, NULL);
+
+ if (!(sym->flags & SYMBOL_WRITE))
+ continue;
+
+ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
+
+ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+ conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+ }
+ fclose(out);
+ fclose(tristate);
+ fclose(out_h);
+
+ name = getenv("KCONFIG_AUTOHEADER");
+ if (!name)
+ name = "include/generated/autoconf.h";
+ if (rename(".tmpconfig.h", name))
+ return 1;
+ name = getenv("KCONFIG_TRISTATE");
+ if (!name)
+ name = "include/config/tristate.conf";
+ if (rename(".tmpconfig_tristate", name))
+ return 1;
+ name = conf_get_autoconfig_name();
+ /*
+ * This must be the last step, kbuild has a dependency on auto.conf
+ * and this marks the successful completion of the previous steps.
+ */
+ if (rename(".tmpconfig", name))
+ return 1;
+
+ return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+ int _sym_change_count = sym_change_count;
+ sym_change_count = count;
+ if (conf_changed_callback &&
+ (bool)_sym_change_count != (bool)count)
+ conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+ sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+ return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+static void randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = (rand() % cnt);
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ }
+ else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+}
+
+static void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+}
+
+void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym))
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+ sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ randomize_choice_values(csym);
+ else
+ set_all_choice_values(csym);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+#define DEBUG_EXPR 0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ struct expr *e = calloc(1, sizeof(*e));
+ e->type = E_SYMBOL;
+ e->left.sym = sym;
+ return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+ struct expr *e = calloc(1, sizeof(*e));
+ e->type = type;
+ e->left.expr = ce;
+ return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+ struct expr *e = calloc(1, sizeof(*e));
+ e->type = type;
+ e->left.expr = e1;
+ e->right.expr = e2;
+ return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+ struct expr *e = calloc(1, sizeof(*e));
+ e->type = type;
+ e->left.sym = s1;
+ e->right.sym = s2;
+ return e;
+}
+
+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;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+ struct expr *e;
+
+ if (!org)
+ return NULL;
+
+ e = malloc(sizeof(*org));
+ memcpy(e, org, sizeof(*org));
+ switch (org->type) {
+ case E_SYMBOL:
+ e->left = org->left;
+ break;
+ case E_NOT:
+ e->left.expr = expr_copy(org->left.expr);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ e->left.sym = org->left.sym;
+ e->right.sym = org->right.sym;
+ break;
+ case E_AND:
+ case E_OR:
+ case E_LIST:
+ e->left.expr = expr_copy(org->left.expr);
+ e->right.expr = expr_copy(org->right.expr);
+ break;
+ default:
+ printf("can't copy type %d\n", e->type);
+ free(e);
+ e = NULL;
+ break;
+ }
+
+ return e;
+}
+
+void expr_free(struct expr *e)
+{
+ if (!e)
+ return;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ break;
+ case E_NOT:
+ expr_free(e->left.expr);
+ return;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ break;
+ case E_OR:
+ case E_AND:
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ break;
+ default:
+ printf("how to free type %d?\n", e->type);
+ break;
+ }
+ free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+ if (e1->type == type) {
+ __expr_eliminate_eq(type, &e1->left.expr, &e2);
+ __expr_eliminate_eq(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ __expr_eliminate_eq(type, &e1, &e2->left.expr);
+ __expr_eliminate_eq(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym &&
+ (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+ return;
+ if (!expr_eq(e1, e2))
+ return;
+ trans_count++;
+ expr_free(e1); expr_free(e2);
+ switch (type) {
+ case E_OR:
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ break;
+ case E_AND:
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+ if (!e1 || !e2)
+ return;
+ switch (e1->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e1->type, ep1, ep2);
+ default:
+ ;
+ }
+ if (e1->type != e2->type) switch (e2->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e2->type, ep1, ep2);
+ default:
+ ;
+ }
+ e1 = expr_eliminate_yn(e1);
+ e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+ int res, old_count;
+
+ if (e1->type != e2->type)
+ return 0;
+ switch (e1->type) {
+ case E_EQUAL:
+ 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:
+ e1 = expr_copy(e1);
+ e2 = expr_copy(e2);
+ old_count = trans_count;
+ expr_eliminate_eq(&e1, &e2);
+ res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym);
+ expr_free(e1);
+ expr_free(e2);
+ trans_count = old_count;
+ return res;
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+
+ if (DEBUG_EXPR) {
+ expr_fprint(e1, stdout);
+ printf(" = ");
+ expr_fprint(e2, stdout);
+ printf(" ?\n");
+ }
+
+ return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (e) switch (e->type) {
+ case E_AND:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ break;
+ case E_OR:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_AND:
+ case E_OR:
+ case E_NOT:
+ e->left.expr = expr_trans_bool(e->left.expr);
+ e->right.expr = expr_trans_bool(e->right.expr);
+ break;
+ case E_UNEQUAL:
+ // FOO!=n -> FOO
+ if (e->left.sym->type == S_TRISTATE) {
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ }
+ }
+ 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 expr_copy(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 && sym1 == sym2) {
+ 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 expr_copy(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;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp;
+
+ if (e1->type == type) {
+ expr_eliminate_dups1(type, &e1->left.expr, &e2);
+ expr_eliminate_dups1(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups1(type, &e1, &e2->left.expr);
+ expr_eliminate_dups1(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e1->type, &e1, &e1);
+ default:
+ ;
+ }
+
+ switch (type) {
+ case E_OR:
+ tmp = expr_join_or(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ case E_AND:
+ tmp = expr_join_and(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp, *tmp1, *tmp2;
+
+ if (e1->type == type) {
+ expr_eliminate_dups2(type, &e1->left.expr, &e2);
+ expr_eliminate_dups2(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups2(type, &e1, &e2->left.expr);
+ expr_eliminate_dups2(type, &e1, &e2->right.expr);
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO || BAR) && (!FOO && !BAR) -> n
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_and(&tmp1, &tmp2);
+ if (expr_is_yes(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_no);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ case E_AND:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO && BAR) || (!FOO || !BAR) -> y
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_or(&tmp1, &tmp2);
+ if (expr_is_no(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+ int oldcount;
+ if (!e)
+ return e;
+
+ oldcount = trans_count;
+ while (1) {
+ trans_count = 0;
+ switch (e->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e->type, &e, &e);
+ expr_eliminate_dups2(e->type, &e, &e);
+ default:
+ ;
+ }
+ if (!trans_count)
+ break;
+ e = expr_eliminate_yn(e);
+ }
+ trans_count = oldcount;
+ return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ case E_SYMBOL:
+ case E_LIST:
+ break;
+ default:
+ e->left.expr = expr_transform(e->left.expr);
+ e->right.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) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_NOT:
+ switch (e->left.expr->type) {
+ case E_NOT:
+ // !!a -> a
+ tmp = e->left.expr->left.expr;
+ free(e->left.expr);
+ free(e);
+ e = tmp;
+ e = expr_transform(e);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ // !a='x' -> a!='x'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+ break;
+ case E_OR:
+ // !(a || b) -> !a && !b
+ tmp = e->left.expr;
+ e->type = E_AND;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_AND:
+ // !(a && b) -> !a || !b
+ tmp = e->left.expr;
+ e->type = E_OR;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_SYMBOL:
+ if (e->left.expr->left.sym == &symbol_yes) {
+ // !'y' -> 'n'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_mod) {
+ // !'m' -> 'm'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_mod;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_no) {
+ // !'n' -> 'y'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return 0;
+
+ 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_UNEQUAL:
+ return dep->left.sym == sym ||
+ dep->right.sym == sym;
+ case E_NOT:
+ return expr_contains_symbol(dep->left.expr, sym);
+ default:
+ ;
+ }
+ return 0;
+}
+
+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;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_AND, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_OR, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ if (e1->type == type) {
+ expr_extract_eq(type, ep, &e1->left.expr, &e2);
+ expr_extract_eq(type, ep, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_extract_eq(type, ep, ep1, &e2->left.expr);
+ expr_extract_eq(type, ep, ep1, &e2->right.expr);
+ return;
+ }
+ if (expr_eq(e1, e2)) {
+ *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+ expr_free(e2);
+ if (type == E_AND) {
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ } else if (type == E_OR) {
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ }
+ }
+#undef e1
+#undef e2
+}
+
+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_EQUAL:
+ if (type == E_EQUAL) {
+ if (sym == &symbol_yes)
+ return expr_copy(e);
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_no);
+ if (sym == &symbol_no)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ } else {
+ if (sym == &symbol_yes)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_yes);
+ if (sym == &symbol_no)
+ return expr_copy(e);
+ }
+ break;
+ case E_SYMBOL:
+ return expr_alloc_comp(type, e->left.sym, sym);
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+ return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+ tristate val1, val2;
+ const char *str1, *str2;
+
+ if (!e)
+ return yes;
+
+ 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:
+ 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);
+ return !strcmp(str1, str2) ? yes : no;
+ case E_UNEQUAL:
+ 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);
+ return !strcmp(str1, str2) ? no : yes;
+ default:
+ printf("expr_calc_value: %d?\n", e->type);
+ return no;
+ }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+ return 1;
+#else
+ if (t1 == t2)
+ return 0;
+ switch (t1) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ if (t2 == E_NOT)
+ return 1;
+ case E_NOT:
+ if (t2 == E_AND)
+ return 1;
+ case E_AND:
+ if (t2 == E_OR)
+ return 1;
+ case E_OR:
+ if (t2 == E_LIST)
+ return 1;
+ case E_LIST:
+ if (t2 == 0)
+ return 1;
+ default:
+ return -1;
+ }
+ printf("[%dgt%d?]", t1, t2);
+ return 0;
+#endif
+}
+
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+ if (e == NULL)
+ return NULL;
+
+ while (e->type != E_SYMBOL)
+ e = e->left.expr;
+
+ return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+ struct expr *ret;
+
+ switch (e1->type) {
+ case E_OR:
+ return expr_alloc_and(
+ expr_simplify_unmet_dep(e1->left.expr, e2),
+ expr_simplify_unmet_dep(e1->right.expr, e2));
+ case E_AND: {
+ struct expr *e;
+ e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+ e = expr_eliminate_dups(e);
+ ret = (!expr_eq(e, e1)) ? e1 : NULL;
+ expr_free(e);
+ break;
+ }
+ default:
+ ret = e1;
+ break;
+ }
+
+ return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+ 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_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_LIST:
+ fn(data, e->right.sym, e->right.sym->name);
+ if (e->left.expr) {
+ fn(data, NULL, " ^ ");
+ expr_print(e->left.expr, fn, data, E_LIST);
+ }
+ 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(struct expr *e, struct gstr *gs)
+{
+ expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+ struct file *next;
+ struct file *parent;
+ const char *name;
+ int lineno;
+};
+
+typedef enum tristate {
+ no, mod, yes
+} tristate;
+
+enum expr_type {
+ E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+ struct expr *expr;
+ struct symbol *sym;
+};
+
+struct expr {
+ enum expr_type type;
+ 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))
+
+#define expr_list_for_each_sym(l, e, s) \
+ for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+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, S_OTHER
+};
+
+/* 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
+};
+
+struct symbol {
+ struct symbol *next;
+ char *name;
+ enum symbol_type type;
+ struct symbol_value curr;
+ struct symbol_value def[S_DEF_COUNT];
+ tristate visible;
+ int flags;
+ struct property *prop;
+ struct expr_value dir_dep;
+ struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST 0x0001 /* symbol is const */
+#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
+#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
+#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE 0x0200 /* ? */
+#define SYMBOL_CHANGED 0x0400 /* ? */
+#define SYMBOL_AUTO 0x1000 /* value from environment variable */
+#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
+#define SYMBOL_HASHSIZE 9973
+
+/* 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
+ */
+enum prop_type {
+ P_UNKNOWN,
+ P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
+ P_COMMENT, /* text associated with a comment */
+ P_MENU, /* prompt associated with a menuconfig option */
+ P_DEFAULT, /* default y */
+ P_CHOICE, /* choice value */
+ P_SELECT, /* select BAR */
+ P_RANGE, /* range 7..100 (for a symbol) */
+ P_ENV, /* value from environment variable */
+ P_SYMBOL, /* where a symbol is defined */
+};
+
+struct property {
+ struct property *next; /* next property - null if last */
+ struct symbol *sym; /* the symbol for which the property is associated */
+ 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_CHOICE,
+ * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+ struct file *file; /* 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_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->text)
+
+struct menu {
+ struct menu *next;
+ struct menu *parent;
+ struct menu *list;
+ struct symbol *sym;
+ struct property *prompt;
+ struct expr *visibility;
+ struct expr *dep;
+ unsigned int flags;
+ char *help;
+ struct file *file;
+ int lineno;
+ void *data;
+};
+
+#define MENU_CHANGED 0x0001
+#define MENU_ROOT 0x0002
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+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);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+ return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+ return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
--- /dev/null
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+
+%%
+mainmenu, T_MAINMENU, TF_COMMAND
+menu, T_MENU, TF_COMMAND
+endmenu, T_ENDMENU, TF_COMMAND
+source, T_SOURCE, TF_COMMAND
+choice, T_CHOICE, TF_COMMAND
+endchoice, T_ENDCHOICE, TF_COMMAND
+comment, T_COMMENT, TF_COMMAND
+config, T_CONFIG, TF_COMMAND
+menuconfig, T_MENUCONFIG, TF_COMMAND
+help, T_HELP, TF_COMMAND
+if, T_IF, TF_COMMAND|TF_PARAM
+endif, T_ENDIF, TF_COMMAND
+depends, T_DEPENDS, TF_COMMAND
+optional, T_OPTIONAL, TF_COMMAND
+default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
+prompt, T_PROMPT, TF_COMMAND
+tristate, T_TYPE, TF_COMMAND, S_TRISTATE
+def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
+bool, T_TYPE, TF_COMMAND, S_BOOLEAN
+boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
+def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
+int, T_TYPE, TF_COMMAND, S_INT
+hex, T_TYPE, TF_COMMAND, S_HEX
+string, T_TYPE, TF_COMMAND, S_STRING
+select, T_SELECT, TF_COMMAND
+range, T_RANGE, TF_COMMAND
+visible, T_VISIBLE, TF_COMMAND
+option, T_OPTION, TF_COMMAND
+on, T_ON, TF_PARAM
+modules, T_OPT_MODULES, TF_OPTION
+defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
+env, T_OPT_ENV, TF_OPTION
+%%
--- /dev/null
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault perf-report perf-report
+%option noinput
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = malloc(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 = realloc(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 = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+%}
+
+ws [ \n\t]
+n [A-Za-z0-9_]
+
+%%
+ int str = 0;
+ int ts, i;
+
+[ \t]*#.*\n |
+[ \t]*\n {
+ current_file->lineno++;
+ return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+ {
+ BEGIN(COMMAND);
+}
+
+. {
+ unput(yytext[0]);
+ BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+ {n}+ {
+ const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ .
+ \n {
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+}
+
+<PARAM>{
+ "&&" return T_AND;
+ "||" return T_OR;
+ "(" return T_OPEN_PAREN;
+ ")" return T_CLOSE_PAREN;
+ "!" return T_NOT;
+ "=" return T_EQUAL;
+ "!=" return T_UNEQUAL;
+ \"|\' {
+ str = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ --- /* ignore */
+ ({n}|[-/.])+ {
+ const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ #.* /* comment */
+ \\\n current_file->lineno++;
+ .
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<STRING>{
+ [^'"\\\n]+/\n {
+ append_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ [^'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.?/\n {
+ append_string(yytext + 1, yyleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (str == yytext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ 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] {
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ current_file->lineno++;
+ 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>> {
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.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) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ for (iter = current_file->parent; iter; iter = iter->parent ) {
+ if (!strcmp(current_file->name,iter->name) ) {
+ printf("%s:%d: recursive inclusion detected. "
+ "Inclusion path:\n current file : '%s'\n",
+ zconf_curname(), zconf_lineno(),
+ zconf_curname());
+ iter = current_file->parent;
+ while (iter && \
+ strcmp(iter->name,current_file->name)) {
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno-1);
+ iter = iter->parent;
+ }
+ if (iter)
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno+1);
+ exit(1);
+ }
+ }
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define P(name,type,arg) extern type name arg
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#ifndef PACKAGE
+#define PACKAGE "linux"
+#endif
+
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+
+#define TF_COMMAND 0x0001
+#define TF_PARAM 0x0002
+#define TF_OPTION 0x0004
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+#define T_OPT_MODULES 1
+#define T_OPT_DEFCONFIG_LIST 2
+#define T_OPT_ENV 3
+
+struct kconf_id {
+ int name;
+ int token;
+ unsigned int flags;
+ enum symbol_type stype;
+};
+
+extern int zconfdebug;
+
+int zconfparse(void);
+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);
+int zconf_lineno(void);
+const char *zconf_curname(void);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+void conf_set_all_new_symbols(enum conf_def_mode mode);
+
+struct conf_printer {
+ void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+ void (*print_comment)(FILE *, const char *, 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");
+}
+
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+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);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+ return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+ return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+ return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
--- /dev/null
+#include <stdarg.h>
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_expand_string_value,const char *,(const char *in));
+P(sym_escape_string_value, const char *,(const char *in));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+static const char nohelp_text[] = "There is no help available for this option.";
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", prop->file->name, 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)
+{
+ struct menu *menu;
+
+ menu = malloc(sizeof(*menu));
+ memset(menu, 0, sizeof(*menu));
+ menu->sym = sym;
+ menu->parent = current_menu;
+ menu->file = current_file;
+ menu->lineno = zconf_lineno();
+
+ *last_entry_ptr = menu;
+ last_entry_ptr = &menu->next;
+ current_entry = menu;
+ if (sym)
+ menu_add_symbol(P_SYMBOL, sym, NULL);
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+ menu_end_entry();
+ last_entry_ptr = ¤t_entry->list;
+ return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = ¤t_menu->next;
+ current_menu = current_menu->parent;
+}
+
+static struct expr *menu_check_dep(struct expr *e)
+{
+ if (!e)
+ return e;
+
+ switch (e->type) {
+ case E_NOT:
+ e->left.expr = menu_check_dep(e->left.expr);
+ break;
+ case E_OR:
+ case E_AND:
+ e->left.expr = menu_check_dep(e->left.expr);
+ e->right.expr = menu_check_dep(e->right.expr);
+ 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, menu_check_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, "type of '%s' redefined from '%s' to '%s'",
+ sym->name ? sym->name : "<choice>",
+ sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+ struct property *prop = prop_alloc(type, current_entry->sym);
+
+ prop->menu = current_entry;
+ prop->expr = expr;
+ prop->visible.expr = menu_check_dep(dep);
+
+ if (prompt) {
+ if (isspace(*prompt)) {
+ prop_warn(prop, "leading whitespace ignored");
+ while (isspace(*prompt))
+ prompt++;
+ }
+ if (current_entry->prompt && current_entry != &rootmenu)
+ 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;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+ return menu_add_prop(type, prompt, NULL, dep);
+}
+
+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, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+ struct property *prop;
+
+ switch (token) {
+ case T_OPT_MODULES:
+ prop = prop_alloc(P_DEFAULT, modules_sym);
+ prop->expr = expr_alloc_symbol(current_entry->sym);
+ break;
+ case T_OPT_DEFCONFIG_LIST:
+ if (!sym_defconfig_list)
+ sym_defconfig_list = current_entry->sym;
+ else if (sym_defconfig_list != current_entry->sym)
+ zconf_error("trying to redefine defconfig symbol");
+ break;
+ case T_OPT_ENV:
+ prop_add_env(arg);
+ break;
+ }
+}
+
+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;
+ 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);
+ }
+ break;
+ case P_SELECT:
+ sym2 = prop_get_symbol(prop);
+ if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+ prop_warn(prop,
+ "config symbol '%s' uses select, but is "
+ "not boolean or tristate", sym->name);
+ else if (sym2->type != S_UNKNOWN &&
+ sym2->type != S_BOOLEAN &&
+ sym2->type != S_TRISTATE)
+ prop_warn(prop,
+ "'%s' has wrong type. 'select' only "
+ "accept arguments of boolean and "
+ "tristate type", sym2->name);
+ 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:
+ ;
+ }
+ }
+}
+
+void menu_finalize(struct menu *parent)
+{
+ struct menu *menu, *last_menu;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+ sym = parent->sym;
+ if (parent->list) {
+ if (sym && sym_is_choice(sym)) {
+ if (sym->type == S_UNKNOWN) {
+ /* find the first choice value to find out choice type */
+ current_entry = parent;
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (menu->sym && menu->sym->type != S_UNKNOWN) {
+ menu_set_type(menu->sym->type);
+ break;
+ }
+ }
+ }
+ /* set the type of the remaining choice values */
+ for (menu = parent->list; menu; menu = menu->next) {
+ current_entry = menu;
+ if (menu->sym && menu->sym->type == S_UNKNOWN)
+ menu_set_type(sym->type);
+ }
+ parentdep = expr_alloc_symbol(sym);
+ } else if (parent->prompt)
+ parentdep = parent->prompt->visible.expr;
+ else
+ parentdep = parent->dep;
+
+ for (menu = parent->list; menu; menu = menu->next) {
+ basedep = expr_transform(menu->dep);
+ basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+ basedep = expr_eliminate_dups(basedep);
+ menu->dep = basedep;
+ if (menu->sym)
+ prop = menu->sym->prop;
+ else
+ prop = menu->prompt;
+ for (; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ dep = expr_transform(prop->visible.expr);
+ dep = expr_alloc_and(expr_copy(basedep), dep);
+ dep = expr_eliminate_dups(dep);
+ if (menu->sym && menu->sym->type != S_TRISTATE)
+ dep = expr_trans_bool(dep);
+ prop->visible.expr = dep;
+ 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), expr_copy(dep)));
+ }
+ }
+ }
+ for (menu = parent->list; menu; menu = menu->next)
+ menu_finalize(menu);
+ } else if (sym) {
+ basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+ basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+ basedep = expr_eliminate_dups(expr_transform(basedep));
+ 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))
+ break;
+ if (expr_depends_symbol(dep, sym))
+ goto next;
+ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+ dep = expr_eliminate_dups(expr_transform(dep));
+ dep2 = expr_copy(basedep);
+ expr_eliminate_eq(&dep, &dep2);
+ expr_free(dep);
+ if (!expr_is_yes(dep2)) {
+ expr_free(dep2);
+ break;
+ }
+ expr_free(dep2);
+ next:
+ menu_finalize(menu);
+ 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) {
+ if (sym && sym_is_choice(sym) &&
+ menu->sym && !sym_is_choice_value(menu->sym)) {
+ current_entry = menu;
+ menu->sym->flags |= SYMBOL_CHOICEVAL;
+ if (!menu->prompt)
+ menu_warn(menu, "choice value must have a prompt");
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT)
+ prop_warn(prop, "defaults for choice "
+ "values not supported");
+ if (prop->menu == menu)
+ continue;
+ if (prop->type == P_PROMPT &&
+ prop->menu->parent->sym != sym)
+ prop_warn(prop, "choice value used outside its choice group");
+ }
+ /* Non-tristate choice values of tristate choices must
+ * depend on the choice being set to Y. The choice
+ * values' dependencies were propagated to their
+ * properties above, so the change here must be re-
+ * propagated.
+ */
+ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+ basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+ menu->dep = expr_alloc_and(basedep, menu->dep);
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+ prop->visible.expr);
+ }
+ }
+ menu_add_symbol(P_CHOICE, sym, NULL);
+ prop = sym_get_choice_prop(sym);
+ for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+ ;
+ *ep = expr_alloc_one(E_LIST, NULL);
+ (*ep)->right.sym = menu->sym;
+ }
+ 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");
+
+ if (sym_is_choice(sym) && !parent->prompt)
+ menu_warn(parent, "choice must have a prompt");
+
+ /* Check properties connected to this symbol */
+ sym_check_prop(sym);
+ sym->flags |= SYMBOL_WARNED;
+ }
+
+ if (sym && !sym_is_optional(sym) && parent->prompt) {
+ sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+ expr_alloc_and(parent->prompt->visible.expr,
+ expr_alloc_symbol(&symbol_mod)));
+ }
+}
+
+bool menu_has_prompt(struct menu *menu)
+{
+ if (!menu->prompt)
+ 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 no;
+ }
+
+ 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)) {
+ if (sym)
+ sym->flags |= SYMBOL_DEF_USER;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+ if (menu->prompt)
+ return menu->prompt->text;
+ else if (menu->sym)
+ return menu->sym->name;
+ return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+ return &rootmenu;
+}
+
+struct menu *menu_get_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;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+ return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+ if (menu->help)
+ return menu->help;
+ else
+ return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+ int i, j;
+ struct menu *submenu[8], *menu;
+
+ str_printf(r, _("Prompt: %s\n"), _(prop->text));
+ str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, _(" Depends on: "));
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
+ menu = prop->menu->parent;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+ submenu[i++] = menu;
+ if (i > 0) {
+ str_printf(r, _(" Location:\n"));
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ str_printf(r, "%*c-> %s", j, ' ', _(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");
+ }
+ }
+}
+
+void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+ bool hit;
+ struct property *prop;
+
+ 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");
+ }
+ }
+ }
+ for_all_prompts(sym, prop)
+ get_prompt_str(r, prop);
+ hit = false;
+ for_all_properties(sym, prop, P_SELECT) {
+ if (!hit) {
+ str_append(r, " Selects: ");
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+ if (sym->rev_dep.expr) {
+ str_append(r, _(" Selected by: "));
+ expr_gstr_print(sym->rev_dep.expr, r);
+ str_append(r, "\n");
+ }
+ str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr)
+{
+ 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);
+ 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_has_help(menu)) {
+ if (sym->name)
+ str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+ help_text = menu_get_help(menu);
+ }
+ str_printf(help, "%s\n", _(help_text));
+ if (sym)
+ get_symbol_str(help, sym);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+ .name = "y",
+ .curr = { "y", yes },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+ .name = "m",
+ .curr = { "m", mod },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+ .name = "n",
+ .curr = { "n", no },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+ .name = "",
+ .curr = { "", no },
+ .flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
+{
+ struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+ prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+ struct symbol *sym;
+ struct utsname uts;
+ static bool inited = false;
+
+ if (inited)
+ return;
+ inited = true;
+
+ uname(&uts);
+
+ sym = sym_lookup("UNAME_RELEASE", 0);
+ sym->type = S_STRING;
+ sym->flags |= SYMBOL_AUTO;
+ sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+ enum symbol_type type = sym->type;
+
+ if (type == S_TRISTATE) {
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ type = S_BOOLEAN;
+ else if (modules_val == no)
+ type = S_BOOLEAN;
+ }
+ return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+ switch (type) {
+ case S_BOOLEAN:
+ return "boolean";
+ 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";
+ case S_OTHER:
+ break;
+ }
+ return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_choices(sym, prop)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_ENV)
+ return prop;
+ return NULL;
+}
+
+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;
+}
+
+static 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 int 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 strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+ struct property *prop;
+ int base, val, val2;
+ char str[64];
+
+ 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 = strtol(sym->curr.val, NULL, base);
+ val2 = sym_get_range_val(prop->expr->left.sym, base);
+ if (val >= val2) {
+ val2 = sym_get_range_val(prop->expr->right.sym, base);
+ if (val <= val2)
+ return;
+ }
+ if (sym->type == S_INT)
+ sprintf(str, "%d", val2);
+ else
+ sprintf(str, "0x%x", val2);
+ sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+ struct property *prop;
+ tristate tri;
+
+ /* 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)
+ 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);
+ }
+}
+
+/*
+ * 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 symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* any of the defaults visible? */
+ for_all_defaults(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 */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ if (def_sym->visible != no)
+ return def_sym;
+
+ /* failed to locate any defaults */
+ return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* first calculate all choice values' visibilities */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ sym_calc_visibility(def_sym);
+
+ /* is the user choice visible? */
+ def_sym = sym->def[S_DEF_USER].val;
+ if (def_sym && def_sym->visible != no)
+ return def_sym;
+
+ def_sym = sym_choice_default(sym);
+
+ if (def_sym == NULL)
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+
+ return def_sym;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+ struct symbol_value newval, oldval;
+ struct property *prop;
+ struct expr *e;
+
+ if (!sym)
+ return;
+
+ if (sym->flags & SYMBOL_VALID)
+ return;
+ sym->flags |= SYMBOL_VALID;
+
+ oldval = sym->curr;
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ newval = symbol_empty.curr;
+ break;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ newval = symbol_no.curr;
+ break;
+ default:
+ sym->curr.val = sym->name;
+ sym->curr.tri = no;
+ return;
+ }
+ if (!sym_is_choice_value(sym))
+ sym->flags &= ~SYMBOL_WRITE;
+
+ sym_calc_visibility(sym);
+
+ /* set default if recursively called */
+ sym->curr = newval;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_is_choice_value(sym) && sym->visible == yes) {
+ prop = sym_get_choice_prop(sym);
+ newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+ } else {
+ if (sym->visible != no) {
+ /* if the symbol is visible use the user value
+ * if available, otherwise try the default value
+ */
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+ sym->visible);
+ 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) {
+ sym->flags |= SYMBOL_WRITE;
+ newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+ prop->visible.tri);
+ }
+ }
+ calc_newval:
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+ struct expr *e;
+ e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+ sym->dir_dep.expr);
+ fprintf(stderr, "warning: (");
+ expr_fprint(e, stderr);
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+ sym->name);
+ expr_fprint(sym->dir_dep.expr, stderr);
+ fprintf(stderr, ")\n");
+ expr_free(e);
+ }
+ 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->flags |= SYMBOL_WRITE;
+ if (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:
+ ;
+ }
+
+ sym->curr = newval;
+ if (sym_is_choice(sym) && newval.tri == yes)
+ sym->curr.val = sym_calc_choice(sym);
+ 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)) {
+ struct symbol *choice_sym;
+
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, choice_sym) {
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
+ sym_set_changed(choice_sym);
+ }
+ }
+
+ if (sym->flags & SYMBOL_AUTO)
+ sym->flags &= ~SYMBOL_WRITE;
+}
+
+void sym_clear_all_valid(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_VALID;
+ sym_add_change_count(1);
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+ }
+}
+
+void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(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;
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ return val == yes;
+ 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 (oldval != val && !sym_tristate_within_range(sym, val))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+ /*
+ * setting a choice value also resets the new flag of the choice
+ * symbol and all other choice values.
+ */
+ if (sym_is_choice_value(sym) && val == yes) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ struct property *prop;
+ struct expr *e;
+
+ cs->def[S_DEF_USER].val = sym;
+ cs->flags |= SYMBOL_DEF_USER;
+ prop = sym_get_choice_prop(cs);
+ for (e = prop->expr; e; e = e->left.expr) {
+ if (e->right.sym->visible != no)
+ e->right.sym->flags |= SYMBOL_DEF_USER;
+ }
+ }
+
+ sym->def[S_DEF_USER].tri = val;
+ if (oldval != val)
+ sym_clear_all_valid();
+
+ return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+ tristate oldval, newval;
+
+ 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;
+ int 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 = strtol(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 = strtol(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 = malloc(size);
+ *val++ = '0';
+ *val++ = 'x';
+ } else if (!oldval || strcmp(oldval, newval))
+ sym->def[S_DEF_USER].val = val = malloc(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;
+ str = symbol_empty.curr.val;
+
+ /* 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;
+
+ 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:
+ case S_HEX:
+ return str;
+ case S_STRING:
+ return str;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+ return "";
+}
+
+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:
+ sym_calc_value(modules_sym);
+ return (modules_sym->curr.tri == no) ? "n" : "m";
+ case yes:
+ return "y";
+ }
+ break;
+ default:
+ ;
+ }
+ return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+ return sym->visible > sym->rev_dep.tri;
+}
+
+static unsigned strhash(const char *s)
+{
+ /* fnv32 hash */
+ unsigned hash = 2166136261U;
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
+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 = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ return symbol;
+ }
+ new_name = strdup(name);
+ } else {
+ new_name = NULL;
+ hash = 0;
+ }
+
+ symbol = malloc(sizeof(*symbol));
+ memset(symbol, 0, sizeof(*symbol));
+ symbol->name = new_name;
+ symbol->type = S_UNKNOWN;
+ symbol->flags |= flags;
+
+ symbol->next = symbol_hash[hash];
+ symbol_hash[hash] = symbol;
+
+ 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 = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ !(symbol->flags & SYMBOL_CONST))
+ break;
+ }
+
+ return symbol;
+}
+
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+ const char *src;
+ char *res;
+ size_t reslen;
+
+ reslen = strlen(in) + 1;
+ res = malloc(reslen);
+ res[0] = '\0';
+
+ while ((src = strchr(in, '$'))) {
+ char *p, name[SYMBOL_MAXLENGTH];
+ const char *symval = "";
+ struct symbol *sym;
+ size_t newlen;
+
+ strncat(res, in, src - in);
+ src++;
+
+ p = name;
+ while (isalnum(*src) || *src == '_')
+ *p++ = *src++;
+ *p = '\0';
+
+ sym = sym_find(name);
+ if (sym != NULL) {
+ sym_calc_value(sym);
+ symval = sym_get_string_value(sym);
+ }
+
+ newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+ if (newlen > reslen) {
+ reslen = newlen;
+ res = realloc(res, reslen);
+ }
+
+ strcat(res, symval);
+ in = src;
+ }
+ strcat(res, in);
+
+ return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+ const char *p;
+ size_t reslen;
+ char *res;
+ size_t l;
+
+ reslen = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ reslen++;
+ p++;
+ }
+
+ res = malloc(reslen);
+ res[0] = '\0';
+
+ strcat(res, "\"");
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ strncat(res, p, l);
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(res, "\\");
+ strncat(res, p++, 1);
+ }
+
+ strcat(res, "\"");
+ return res;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+ struct symbol *sym, **sym_arr = NULL;
+ int i, cnt, size;
+ regex_t re;
+
+ cnt = size = 0;
+ /* Skip if empty */
+ if (strlen(pattern) == 0)
+ return NULL;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+ return NULL;
+
+ for_all_symbols(i, sym) {
+ if (sym->flags & SYMBOL_CONST || !sym->name)
+ continue;
+ if (regexec(&re, sym->name, 0, NULL, 0))
+ continue;
+ if (cnt + 1 >= size) {
+ void *tmp = sym_arr;
+ size += 16;
+ sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+ if (!sym_arr) {
+ free(tmp);
+ return NULL;
+ }
+ }
+ sym_calc_value(sym);
+ sym_arr[cnt++] = sym;
+ }
+ if (sym_arr)
+ sym_arr[cnt] = NULL;
+ 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 inser() 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 *menu = NULL;
+ struct property *prop;
+ struct dep_stack cv_stack;
+
+ if (sym_is_choice_value(last_sym)) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = prop_get_symbol(sym_get_choice_prop(last_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;
+ prop = stack->prop;
+ if (prop == NULL)
+ prop = stack->sym->prop;
+
+ /* for choice values find the menu entry (used below) */
+ if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+ for (prop = sym->prop; prop; prop = prop->next) {
+ menu = prop->menu;
+ if (prop->menu)
+ break;
+ }
+ }
+ if (stack->sym == last_sym)
+ fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+ prop->file->name, prop->lineno);
+ if (stack->expr) {
+ fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(prop->type),
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (stack->prop) {
+ fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice(sym)) {
+ fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice_value(sym)) {
+ fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else {
+ fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ }
+ }
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(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_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;
+ }
+ printf("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);
+
+ sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+ if (sym2)
+ goto out;
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_CHOICE || prop->type == P_SELECT)
+ 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 symbol *sym, *sym2;
+ struct property *prop;
+ struct expr *e;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
+
+ prop = sym_get_choice_prop(choice);
+ expr_list_for_each_sym(prop->expr, e, sym)
+ 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;
+
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ sym2 = sym_check_sym_deps(sym);
+ if (sym2)
+ break;
+ }
+out:
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2 && sym_is_choice_value(sym2) &&
+ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+ sym2 = choice;
+
+ dep_stack_remove();
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ sym_check_print_recursive(sym);
+ return sym;
+ }
+ if (sym->flags & SYMBOL_CHECKED)
+ return NULL;
+
+ if (sym_is_choice_value(sym)) {
+ struct dep_stack stack;
+
+ /* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
+ prop = sym_get_choice_prop(sym);
+ sym2 = sym_check_deps(prop_get_symbol(prop));
+ 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;
+ }
+
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
+
+ return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+ struct property *prop;
+ struct property **propp;
+
+ prop = malloc(sizeof(*prop));
+ memset(prop, 0, sizeof(*prop));
+ prop->type = type;
+ prop->sym = sym;
+ prop->file = current_file;
+ prop->lineno = zconf_lineno();
+
+ /* append property to the prop list of symbol */
+ if (sym) {
+ for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+ ;
+ *propp = prop;
+ }
+
+ return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+ if (prop->expr && (prop->expr->type == E_SYMBOL ||
+ prop->expr->type == E_LIST))
+ 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_ENV:
+ return "env";
+ case P_COMMENT:
+ return "comment";
+ case P_MENU:
+ return "menu";
+ case P_DEFAULT:
+ return "default";
+ case P_CHOICE:
+ return "choice";
+ case P_SELECT:
+ return "select";
+ case P_RANGE:
+ return "range";
+ case P_SYMBOL:
+ return "symbol";
+ case P_UNKNOWN:
+ break;
+ }
+ return "unknown";
+}
+
+static void prop_add_env(const char *env)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ char *p;
+
+ sym = current_entry->sym;
+ sym->flags |= SYMBOL_AUTO;
+ for_all_properties(sym, prop, P_ENV) {
+ sym2 = prop_get_symbol(prop);
+ if (strcmp(sym2->name, env))
+ menu_warn(current_entry, "redefining environment symbol from %s",
+ sym2->name);
+ return;
+ }
+
+ prop = prop_alloc(P_ENV, sym);
+ prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+ sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+ sym_env_list->right.sym = sym;
+
+ p = getenv(env);
+ if (p)
+ sym_add_default(sym, p);
+ else
+ menu_warn(current_entry, "environment variable %s undefined", env);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+ struct file *file;
+ const char *file_name = sym_expand_string_value(name);
+
+ for (file = file_list; file; file = file->next) {
+ if (!strcmp(name, file->name)) {
+ free((void *)file_name);
+ return file;
+ }
+ }
+
+ file = malloc(sizeof(*file));
+ memset(file, 0, sizeof(*file));
+ file->name = file_name;
+ file->next = file_list;
+ file_list = file;
+ return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+ struct symbol *sym, *env_sym;
+ struct expr *e;
+ struct file *file;
+ FILE *out;
+
+ if (!name)
+ name = ".kconfig.d";
+ out = fopen("..config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n%s: \\\n"
+ "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+ expr_list_for_each_sym(sym_env_list, e, sym) {
+ struct property *prop;
+ const char *value;
+
+ prop = sym_get_env_prop(sym);
+ env_sym = prop_get_symbol(prop);
+ if (!env_sym)
+ continue;
+ value = getenv(env_sym->name);
+ if (!value)
+ value = "";
+ fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+ fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+ fprintf(out, "endif\n");
+ }
+
+ fprintf(out, "\n$(deps_config): ;\n");
+ fclose(out);
+ rename("..config.tmp", name);
+ return 0;
+}
+
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+ struct gstr gs;
+ gs.s = malloc(sizeof(char) * 64);
+ gs.len = 64;
+ gs.max_width = 0;
+ strcpy(gs.s, "\0");
+ return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+ struct gstr gs;
+ gs.s = strdup(s);
+ gs.len = strlen(s) + 1;
+ gs.max_width = 0;
+ return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+ if (gs->s)
+ 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 = realloc(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 */
+const char *str_get(struct gstr *gs)
+{
+ return gs->s;
+}
+
--- /dev/null
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+%}
+%expect 30
+
+%union
+{
+ char *string;
+ struct file *file;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ const struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ $$->file->name, $$->lineno);
+ if (current_menu == $$)
+ menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "hconf.c"
+%}
+
+%%
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
+
+stmt_list:
+ /* empty */
+ | stmt_list common_stmt
+ | stmt_list choice_stmt
+ | stmt_list menu_stmt
+ | stmt_list end { zconf_error("unexpected end statement"); }
+ | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
+ | stmt_list option_name error T_EOL
+{
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+ | stmt_list error T_EOL { zconf_error("invalid statement"); }
+;
+
+option_name:
+ T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
+;
+
+common_stmt:
+ T_EOL
+ | if_stmt
+ | comment_stmt
+ | config_stmt
+ | menuconfig_stmt
+ | source_stmt
+;
+
+option_error:
+ T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
+ | error T_EOL { zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+ /* empty */
+ | config_option_list config_option
+ | config_option_list symbol_option
+ | config_option_list depends
+ | config_option_list help
+ | config_option_list option_error
+ | config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ if ($1->stype != S_UNKNOWN)
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+ menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_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", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+ /* empty */
+ | symbol_option_list T_WORD symbol_option_arg
+{
+ const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+ if (id && id->flags & TF_OPTION)
+ menu_add_option(id->token, $3);
+ else
+ zconfprint("warning: ignoring unknown option %s", $2);
+ free($2);
+};
+
+symbol_option_arg:
+ /* empty */ { $$ = NULL; }
+ | T_EQUAL prompt { $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+ struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+ $$ = menu_add_menu();
+};
+
+choice_end: end
+{
+ if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+ /* empty */
+ | choice_option_list choice_option
+ | choice_option_list depends
+ | choice_option_list help
+ | choice_option_list T_EOL
+ | choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+ } else
+ YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+ if ($1->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n",
+ zconf_curname(), zconf_lineno());
+ } else
+ YYERROR;
+};
+
+choice_block:
+ /* empty */
+ | choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep($2);
+ $$ = menu_add_menu();
+};
+
+if_end: end
+{
+ if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+ /* empty */
+ | if_block common_stmt
+ | if_block menu_stmt
+ | if_block choice_stmt
+;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+ menu_add_prompt(P_MENU, $2, NULL);
+};
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_MENU, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu visibility_list depends_list
+{
+ $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+ if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+ /* empty */
+ | menu_block common_stmt
+ | menu_block menu_stmt
+ | menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+ zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_COMMENT, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+ menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+ current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+ /* empty */
+ | depends_list depends
+ | depends_list T_EOL
+ | depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+ menu_add_dep($3);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* visibility option */
+
+visibility_list:
+ /* empty */
+ | visibility_list visible
+ | visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+ menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+ /* empty */
+ | prompt if_expr
+{
+ menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt: T_WORD
+ | T_WORD_QUOTE
+;
+
+end: T_ENDMENU T_EOL { $$ = $1; }
+ | T_ENDCHOICE T_EOL { $$ = $1; }
+ | T_ENDIF T_EOL { $$ = $1; }
+;
+
+nl:
+ T_EOL
+ | nl T_EOL
+;
+
+if_expr: /* empty */ { $$ = NULL; }
+ | T_IF expr { $$ = $2; }
+;
+
+expr: symbol { $$ = expr_alloc_symbol($1); }
+ | 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); }
+;
+
+symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
+ | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */ { $$ = NULL; }
+ | T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ _menu_init();
+ modules_sym = sym_lookup(NULL, 0);
+ modules_sym->type = S_BOOLEAN;
+ modules_sym->flags |= SYMBOL_AUTO;
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+ if (getenv("ZCONF_DEBUG"))
+ zconfdebug = 1;
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ if (!modules_sym->prop) {
+ struct property *prop;
+
+ prop = prop_alloc(P_DEFAULT, modules_sym);
+ prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+ }
+
+ rootmenu.prompt->text = _(rootmenu.prompt->text);
+ rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (sym_check_deps(sym))
+ zconfnerrs++;
+ }
+ if (zconfnerrs)
+ exit(1);
+ sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
+{
+ if (id->token != endtoken) {
+ zconf_error("unexpected '%s' within %s block",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconf_error("'%s' in different file than '%s'",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->file->name, current_menu->lineno,
+ zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ zconfnerrs++;
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, 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, 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(" boolean\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_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ case P_SELECT:
+ fputs( " select ", 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;
+ }
+ }
+ }
+}
+
+#include "lconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+++ /dev/null
-#
-# Generated files
-#
-lxdialog
+++ /dev/null
-This is NOT the official version of dialog. This version has been
-significantly modified from the original. It is for use by the Linux
-kernel configuration script. Please do not bother Savio Lam with
-questions about this program.
+++ /dev/null
-noinst_LIBRARIES = liblxdialog.a
-
-liblxdialog_a_SOURCES = \
- checklist.c \
- dialog.h \
- inputbox.c \
- menubox.c \
- textbox.c \
- util.c \
- yesno.c
-
-liblxdialog_a_CPPFLAGS = $(AM_CPPFLAGS) \
- -DCURSES_LOC='"${CURSES_LOC}"' \
- $(GETTEXT)
+++ /dev/null
-/*
- * 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)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#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, gettext("Select"), y, x, selected == 0);
- print_button(dialog, gettext(" 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 + 6))
- return -ERRDISPLAYTOOSMALL;
- if (getmaxx(stdscr) < (width + 6))
- return -ERRDISPLAYTOOSMALL;
-
- max_choice = MIN(list_height, item_count());
-
- /* center dialog box on screen */
- x = (COLS - width) / 2;
- y = (LINES - 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);
-
- wnoutrefresh(dialog);
- wnoutrefresh(list);
- doupdate();
-
- 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 */
-}
+++ /dev/null
-/*
- * dialog.h -- common declarations for all dialog modules
- *
- * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#ifndef KBUILD_NO_NLS
-# include <libintl.h>
-#else
-# define gettext(Msgid) ((const char *) (Msgid))
-#endif
-
-#ifdef __sun__
-#define CURS_MACROS
-#endif
-#include CURSES_LOC
-
-/*
- * Colors in ncurses 1.9.9e do not work properly since foreground and
- * background colors are OR'd rather than separately masked. This version
- * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
- * with standard curses. The simplest fix (to make this work with standard
- * curses) uses the wbkgdset() function, not used in the original hack.
- * Turn it off if we're building with 1.9.9e, since it just confuses things.
- */
-#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
-#define OLD_NCURSES 1
-#undef wbkgdset
-#define wbkgdset(w,p) /*nothing */
-#else
-#define OLD_NCURSES 0
-#endif
-
-#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 dialog_info {
- const char *backtitle;
- 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 inputbox_border;
- struct dialog_color searchbox;
- struct dialog_color searchbox_title;
- struct dialog_color searchbox_border;
- 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[];
-
-/*
- * 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]; /* promtp 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);
-
-int init_dialog(const char *backtitle);
-void set_dialog_backtitle(const char *backtitle);
-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 *file, int height, int width);
-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);
-extern char dialog_input_result[];
-int dialog_inputbox(const char *title, const char *prompt, int height,
- int width, const char *init);
-
-/*
- * This is the base for fictitious keys, which activate
- * the buttons.
- *
- * Mouse-generated keys are the following:
- * -- the first 32 are used as numbers, in addition to '0'-'9'
- * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
- * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
- */
-#define M_EVENT (KEY_MAX+1)
+++ /dev/null
-/*
- * 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)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#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, gettext(" Ok "), y, x, selected == 0);
- print_button(dialog, gettext(" 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, scroll = 0, key = 0, button = -1;
- char *instr = dialog_input_result;
- WINDOW *dialog;
-
- if (!init)
- instr[0] = '\0';
- else
- strcpy(instr, init);
-
-do_resize:
- if (getmaxy(stdscr) <= (height - 2))
- return -ERRDISPLAYTOOSMALL;
- if (getmaxx(stdscr) <= (width - 2))
- return -ERRDISPLAYTOOSMALL;
-
- /* center dialog box on screen */
- x = (COLS - width) / 2;
- y = (LINES - 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);
-
- input_x = strlen(instr);
-
- if (input_x >= box_width) {
- scroll = input_x - box_width + 1;
- input_x = box_width - 1;
- for (i = 0; i < box_width - 1; i++)
- waddch(dialog, instr[scroll + i]);
- } else {
- 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_LEFT:
- continue;
- case KEY_RIGHT:
- continue;
- case KEY_BACKSPACE:
- case 127:
- if (input_x || scroll) {
- wattrset(dialog, dlg.inputbox.atr);
- if (!input_x) {
- scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
- wmove(dialog, box_y, box_x);
- for (i = 0; i < box_width; i++)
- waddch(dialog,
- instr[scroll + input_x + i] ?
- instr[scroll + input_x + i] : ' ');
- input_x = strlen(instr) - scroll;
- } else
- input_x--;
- instr[scroll + input_x] = '\0';
- mvwaddch(dialog, box_y, input_x + box_x, ' ');
- wmove(dialog, box_y, input_x + box_x);
- wrefresh(dialog);
- }
- continue;
- default:
- if (key < 0x100 && isprint(key)) {
- if (scroll + input_x < MAX_LEN) {
- wattrset(dialog, dlg.inputbox.atr);
- instr[scroll + input_x] = key;
- instr[scroll + input_x + 1] = '\0';
- if (input_x == box_width - 1) {
- scroll++;
- wmove(dialog, box_y, box_x);
- for (i = 0; i < box_width - 1; i++)
- waddch(dialog, instr [scroll + i]);
- } else {
- wmove(dialog, box_y, input_x++ + box_x);
- waddch(dialog, key);
- }
- 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 */
-}
+++ /dev/null
-/*
- * 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)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * 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);
-#if OLD_NCURSES
- {
- int i;
- for (i = 0; i < menu_width; i++)
- waddch(win, ' ');
- }
-#else
- wclrtoeol(win);
-#endif
- 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 - 16;
- int y = height - 2;
-
- print_button(win, gettext("Select"), y, x, selected == 0);
- print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
- print_button(win, gettext(" Help "), y, x + 24, selected == 2);
-
- 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 < 15 || width < 65)
- return -ERRDISPLAYTOOSMALL;
-
- height -= 4;
- width -= 5;
- menu_height = height - 10;
-
- max_choice = MIN(menu_height, item_count());
-
- /* center dialog box on screen */
- x = (COLS - width) / 2;
- y = (LINES - 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 (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)
- ? 2 : (button > 2 ? 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 3;
- case 'n':
- return 4;
- case 'm':
- return 5;
- case ' ':
- return 6;
- case '/':
- return 7;
- case 'z':
- return 8;
- 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 */
-}
+++ /dev/null
-/*
- * 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)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "dialog.h"
-
-static void back_lines(int n);
-static void print_page(WINDOW * win, int height, int width);
-static void print_line(WINDOW * win, int row, int width);
-static char *get_line(void);
-static void print_position(WINDOW * win);
-
-static int hscroll;
-static int begin_reached, end_reached, page_length;
-static const char *buf;
-static const char *page;
-
-/*
- * refresh window content
- */
-static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
- int cur_y, int cur_x)
-{
- print_page(box, boxh, boxw);
- print_position(dialog);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
-}
-
-
-/*
- * Display text from a file in a dialog box.
- */
-int dialog_textbox(const char *title, const char *tbuf,
- int initial_height, int initial_width)
-{
- int i, x, y, cur_x, cur_y, key = 0;
- int height, width, boxh, boxw;
- int passed_end;
- WINDOW *dialog, *box;
-
- 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 */
-
-do_resize:
- getmaxyx(stdscr, height, width);
- if (height < 8 || width < 8)
- 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 = (COLS - width) / 2;
- y = (LINES - 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, gettext(" 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 ((key != KEY_ESC) && (key != '\n')) {
- key = wgetch(dialog);
- switch (key) {
- case 'E': /* Exit */
- case 'e':
- case 'X':
- case 'x':
- delwin(box);
- delwin(dialog);
- return 0;
- 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) {
- back_lines(page_length + 1);
-
- /* We don't call print_page() here but use
- * scrolling to ensure faster screen update.
- * However, 'end_reached' and 'page_length'
- * should still be updated, and 'page' should
- * point to start of next page. This is done
- * by calling get_line() in the following
- * 'for' loop. */
- scrollok(box, TRUE);
- wscrl(box, -1); /* Scroll box region down one line */
- scrollok(box, FALSE);
- page_length = 0;
- passed_end = 0;
- for (i = 0; i < boxh; i++) {
- if (!i) {
- /* print first line of page */
- print_line(box, 0, boxw);
- wnoutrefresh(box);
- } else
- /* Called to update 'end_reached' and 'page' */
- get_line();
- if (!passed_end)
- page_length++;
- if (end_reached && !passed_end)
- passed_end = 1;
- }
-
- print_position(dialog);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
- }
- break;
- case 'B': /* Previous page */
- case 'b':
- 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) {
- begin_reached = 0;
- scrollok(box, TRUE);
- scroll(box); /* Scroll box region up one line */
- scrollok(box, FALSE);
- print_line(box, boxh - 1, boxw);
- wnoutrefresh(box);
- print_position(dialog);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
- }
- break;
- case KEY_NPAGE: /* Next page */
- case ' ':
- 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:
- key = on_key_esc(dialog);
- break;
- case KEY_RESIZE:
- back_lines(height);
- delwin(box);
- delwin(dialog);
- on_key_resize();
- goto do_resize;
- }
- }
- delwin(box);
- delwin(dialog);
- return key; /* ESC pressed */
-}
-
-/*
- * 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++;
- }
-}
-
-/*
- * Print a new page of text. Called by dialog_textbox().
- */
-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 a new line of text. Called by dialog_textbox() and print_page().
- */
-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 */
-#if OLD_NCURSES
- {
- int x = getcurx(win);
- int i;
- for (i = 0; i < width - x; i++)
- waddch(win, ' ');
- }
-#else
- wclrtoeol(win);
-#endif
-}
-
-/*
- * 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') {
- if (!end_reached) {
- 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 pass '\n' */
-
- return line;
-}
-
-/*
- * 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);
-}
+++ /dev/null
-/*
- * util.c
- *
- * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
- * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdarg.h>
-
-#include "dialog.h"
-
-struct dialog_info dlg;
-
-static void set_mono_theme(void)
-{
- dlg.screen.atr = A_NORMAL;
- dlg.shadow.atr = A_NORMAL;
- dlg.dialog.atr = A_NORMAL;
- dlg.title.atr = A_BOLD;
- dlg.border.atr = A_NORMAL;
- 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.button_label_inactive.atr = A_NORMAL;
- dlg.inputbox.atr = A_NORMAL;
- dlg.inputbox_border.atr = A_NORMAL;
- dlg.searchbox.atr = A_NORMAL;
- dlg.searchbox_title.atr = A_BOLD;
- dlg.searchbox_border.atr = A_NORMAL;
- dlg.position_indicator.atr = A_BOLD;
- dlg.menubox.atr = A_NORMAL;
- dlg.menubox_border.atr = A_NORMAL;
- dlg.item.atr = A_NORMAL;
- 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(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
- DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
- DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
- DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
- 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_BLACK, COLOR_BLACK, true);
-
- DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
- DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
-
- DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
- DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
- DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
-
- 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(searchbox_title, COLOR_BLUE, COLOR_WHITE, 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.inputbox_border);
- init_one_color(&dlg.searchbox);
- init_one_color(&dlg.searchbox_title);
- init_one_color(&dlg.searchbox_border);
- 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)
-{
- attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
- /* Display background title if it exists ... - SLH */
- if (dlg.backtitle != NULL) {
- int i;
-
- wattrset(stdscr, dlg.screen.atr);
- mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
- wmove(stdscr, 1, 1);
- for (i = 1; i < COLS - 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 */
- getmaxyx(stdscr, height, width);
- if (height < 19 || width < 80) {
- 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;
-}
-
-/*
- * 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 replaced by spaces. 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 i, prompt_len, room, wlen;
- char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
-
- strcpy(tempstr, prompt);
-
- prompt_len = strlen(tempstr);
-
- /*
- * Remove newlines
- */
- for (i = 0; i < prompt_len; i++) {
- if (tempstr[i] == '\n')
- tempstr[i] = ' ';
- }
-
- 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 = strchr(word, ' ');
- 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 = strchr(sp, ' '))
- || 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);
- 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 thats
- * 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);
-}
+++ /dev/null
-/*
- * 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)
- *
- * 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
- * of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#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, gettext(" Yes "), y, x, selected == 0);
- print_button(dialog, gettext(" 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 + 4))
- return -ERRDISPLAYTOOSMALL;
- if (getmaxx(stdscr) < (width + 4))
- return -ERRDISPLAYTOOSMALL;
-
- /* center dialog box on screen */
- x = (COLS - width) / 2;
- y = (LINES - 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 */
-}
+++ /dev/null
-SUFFIXES = .gperf
-
-noinst_LIBRARIES = libkconfigparser.a
-
-libkconfigparser_a_SOURCES = yconf.y
-dist_EXTRA_libkconfigparser_a_SOURCES = \
- hconf.gperf lconf.l \
- confdata.c menu.c symbol.c util.c \
- expr.c expr.h lkc.h lkc_proto.h
-
-BUILT_SOURCES = hconf.c lconf.c
-
-# Can't use libkconfigparser_a_CPPFLAGS, as it breaks dependencies
-yconf.o: CPPFLAGS+=$(GETTEXT)
-
-.gperf.c:
- $(GPERF) -t --output-file $@ -a -C -E -g -k 1,3,$$ -p -t $<
-
-# The following rule produces a warning:
-# parser/Makefile.am:31: user target `.l.c' defined here...
-# /usr/share/automake-1.11/am/lex.am: ... overrides Automake target
-# `.l.c' defined here
-#
-# This is expected, and can't be avoided (for now).
-# That's because, when working with lex+yacc sources, the default is to
-# build each files searately, and then link them together into the final
-# output. But the Linux kernel's parser simply #include-s the lexer,
-# so we can't put lconf.l into the _SOURCES (it's in EXTRA_SOURCES),
-# and thus automake does not catch the need to call lex.
-# Secondly, when flex is told to change the symbols' prefix (kconfig
-# uses zconf in lieue of the original yy), then the output file is
-# also renamed, but automake does not now that, and make would fail
-# because it would think no file was generated.
-.l.c:
- $(LEXCOMPILE) -o$@ $<
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <sys/stat.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "lkc.h"
-
-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, conf_unsaved;
-
-const char conf_defname[] = "arch/$ARCH/defconfig";
-
-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 *fmt, va_list ap)
-{
- printf("#\n# ");
- vprintf(fmt, ap);
- printf("\n#\n");
-}
-
-static void (*conf_message_callback) (const char *fmt, va_list ap) =
- conf_default_message_callback;
-void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
-{
- conf_message_callback = fn;
-}
-
-static void conf_message(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (conf_message_callback)
- conf_message_callback(fmt, ap);
-}
-
-const char *conf_get_configname(void)
-{
- char *name = getenv("KCONFIG_CONFIG");
-
- return name ? name : ".config";
-}
-
-const char *conf_get_autoconfig_name(void)
-{
- char *name = getenv("KCONFIG_AUTOCONFIG");
-
- return name ? name : "include/config/auto.conf";
-}
-
-static char *conf_expand_value(const char *in)
-{
- struct symbol *sym;
- const char *src;
- static char res_value[SYMBOL_MAXLENGTH];
- char *dst, name[SYMBOL_MAXLENGTH];
-
- res_value[0] = 0;
- dst = name;
- while ((src = strchr(in, '$'))) {
- strncat(res_value, in, src - in);
- src++;
- dst = name;
- while (isalnum(*src) || *src == '_')
- *dst++ = *src++;
- *dst = 0;
- sym = sym_lookup(name, 0);
- sym_calc_value(sym);
- strcat(res_value, sym_get_string_value(sym));
- in = src;
- }
- strcat(res_value, in);
-
- return res_value;
-}
-
-char *conf_get_default_confname(void)
-{
- struct stat buf;
- static char fullname[PATH_MAX+1];
- char *env, *name;
-
- name = conf_expand_value(conf_defname);
- env = getenv(SRCTREE);
- if (env) {
- sprintf(fullname, "%s/%s", env, name);
- if (!stat(fullname, &buf))
- return fullname;
- }
- return name;
-}
-
-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;
- }
- conf_warning("symbol value '%s' invalid for %s", p, sym->name);
- return 1;
- case S_OTHER:
- if (*p != '"') {
- for (p2 = p; *p2 && !isspace(*p2); p2++)
- ;
- sym->type = S_STRING;
- goto done;
- }
- /* fall through */
- case S_STRING:
- if (*p++ != '"')
- break;
- 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:
- done:
- if (sym_string_valid(sym, p)) {
- sym->def[def].val = strdup(p);
- sym->flags |= def_flags;
- } else {
- conf_warning("symbol value '%s' invalid for %s", p, sym->name);
- return 1;
- }
- break;
- default:
- ;
- }
- return 0;
-}
-
-int conf_read_simple(const char *name, int def)
-{
- FILE *in = NULL;
- char line[1024];
- char *p, *p2;
- struct symbol *sym;
- int i, def_flags;
-
- if (name) {
- in = zconf_fopen(name);
- } else {
- struct property *prop;
-
- name = conf_get_configname();
- in = zconf_fopen(name);
- if (in)
- goto load;
- sym_add_change_count(1);
- if (!sym_defconfig_list) {
- if (modules_sym)
- sym_calc_value(modules_sym);
- return 1;
- }
-
- for_all_defaults(sym_defconfig_list, prop) {
- if (expr_calc_value(prop->visible.expr) == no ||
- prop->expr->type != E_SYMBOL)
- continue;
- name = conf_expand_value(prop->expr->left.sym->name);
- in = zconf_fopen(name);
- if (in) {
- conf_message(_("using defaults found in %s"),
- name);
- goto load;
- }
- }
- }
- if (!in)
- return 1;
-
-load:
- conf_filename = name;
- conf_lineno = 0;
- conf_warnings = 0;
- conf_unsaved = 0;
-
- def_flags = SYMBOL_DEF << def;
- for_all_symbols(i, sym) {
- sym->flags |= SYMBOL_CHANGED;
- sym->flags &= ~(def_flags|SYMBOL_VALID);
- if (sym_is_choice(sym))
- sym->flags |= def_flags;
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- if (sym->def[def].val)
- free(sym->def[def].val);
- /* fall through */
- default:
- sym->def[def].val = NULL;
- sym->def[def].tri = no;
- }
- }
-
- while (fgets(line, sizeof(line), in)) {
- conf_lineno++;
- sym = NULL;
- if (line[0] == '#') {
- if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
- continue;
- p = strchr(line + 2 + strlen(CONFIG_), ' ');
- if (!p)
- continue;
- *p++ = 0;
- if (strncmp(p, "is not set", 10))
- continue;
- if (def == S_DEF_USER) {
- sym = sym_find(line + 2 + strlen(CONFIG_));
- if (!sym) {
- sym_add_change_count(1);
- goto setsym;
- }
- } else {
- sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_BOOLEAN;
- }
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- sym->def[def].tri = no;
- sym->flags |= def_flags;
- break;
- default:
- ;
- }
- } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
- p = strchr(line + strlen(CONFIG_), '=');
- if (!p)
- continue;
- *p++ = 0;
- p2 = strchr(p, '\n');
- if (p2) {
- *p2-- = 0;
- if (*p2 == '\r')
- *p2 = 0;
- }
- if (def == S_DEF_USER) {
- sym = sym_find(line + strlen(CONFIG_));
- if (!sym) {
- sym_add_change_count(1);
- goto setsym;
- }
- } else {
- sym = sym_lookup(line + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_OTHER;
- }
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- if (conf_set_sym_val(sym, def, def_flags, p))
- continue;
- } else {
- if (line[0] != '\r' && line[0] != '\n')
- conf_warning("unexpected data");
- continue;
- }
-setsym:
- if (sym && sym_is_choice_value(sym)) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- switch (sym->def[def].tri) {
- case no:
- break;
- case mod:
- if (cs->def[def].tri == yes) {
- conf_warning("%s creates inconsistent choice state", sym->name);
- cs->flags &= ~def_flags;
- }
- break;
- case yes:
- if (cs->def[def].tri != no)
- conf_warning("override: %s changes choice state", sym->name);
- cs->def[def].val = sym;
- break;
- }
- cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
- }
- }
- fclose(in);
-
- if (modules_sym)
- sym_calc_value(modules_sym);
- return 0;
-}
-
-int conf_read(const char *name)
-{
- struct symbol *sym, *choice_sym;
- struct property *prop;
- struct expr *e;
- int i, flags;
-
- sym_set_change_count(0);
-
- if (conf_read_simple(name, S_DEF_USER))
- return 1;
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
- goto sym_ok;
- 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))
- break;
- if (!sym_is_choice(sym))
- goto sym_ok;
- /* fall through */
- default:
- if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
- goto sym_ok;
- break;
- }
- } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
- /* no previous value and not saved */
- goto sym_ok;
- conf_unsaved++;
- /* maybe print value in verbose mode... */
- sym_ok:
- if (!sym_is_choice(sym))
- continue;
- /* The choice symbol only has a set value (and thus is not new)
- * if all its visible childs have values.
- */
- prop = sym_get_choice_prop(sym);
- flags = sym->flags;
- expr_list_for_each_sym(prop->expr, e, choice_sym)
- if (choice_sym->visible != no)
- flags &= choice_sym->flags;
- sym->flags &= flags | ~SYMBOL_DEF_USER;
- }
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
- /* Reset values of generates values, so they'll appear
- * as new, if they should become visible, but that
- * doesn't quite work if the Kconfig and the saved
- * configuration disagree.
- */
- if (sym->visible == no && !conf_unsaved)
- sym->flags &= ~SYMBOL_DEF_USER;
- switch (sym->type) {
- case S_STRING:
- case S_INT:
- case S_HEX:
- /* Reset a string value if it's out of range */
- if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
- break;
- sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
- conf_unsaved++;
- break;
- default:
- break;
- }
- }
- }
-
- sym_add_change_count(conf_warnings || conf_unsaved);
-
- return 0;
-}
-
-/*
- * Kconfig configuration printer
- *
- * This printer is used when generating the resulting configuration after
- * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
- * passing a non-NULL argument to the printer.
- *
- */
-static void
-kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (*value == 'n') {
- bool skip_unset = (arg != NULL);
-
- if (!skip_unset)
- fprintf(fp, "# %s%s is not set\n",
- CONFIG_, sym->name);
- return;
- }
- break;
- default:
- break;
- }
-
- fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
-}
-
-static void
-kconfig_print_comment(FILE *fp, const char *value, void *arg)
-{
- const char *p = value;
- size_t l;
-
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, "#");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
- break;
- }
-}
-
-static struct conf_printer kconfig_printer_cb =
-{
- .print_symbol = kconfig_print_symbol,
- .print_comment = kconfig_print_comment,
-};
-
-/*
- * Header printer
- *
- * This printer is used when generating the `include/generated/autoconf.h' file.
- */
-static void
-header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE: {
- const char *suffix = "";
-
- switch (*value) {
- case 'n':
- break;
- case 'm':
- suffix = "_MODULE";
- /* fall through */
- default:
- fprintf(fp, "#define %s%s%s 1\n",
- CONFIG_, sym->name, suffix);
- }
- break;
- }
- case S_HEX: {
- const char *prefix = "";
-
- if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
- prefix = "0x";
- fprintf(fp, "#define %s%s %s%s\n",
- CONFIG_, sym->name, prefix, value);
- break;
- }
- case S_STRING:
- case S_INT:
- fprintf(fp, "#define %s%s %s\n",
- CONFIG_, sym->name, value);
- break;
- default:
- break;
- }
-
-}
-
-static void
-header_print_comment(FILE *fp, const char *value, void *arg)
-{
- const char *p = value;
- size_t l;
-
- fprintf(fp, "/*\n");
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, " *");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
- break;
- }
- fprintf(fp, " */\n");
-}
-
-static struct conf_printer header_printer_cb =
-{
- .print_symbol = header_print_symbol,
- .print_comment = header_print_comment,
-};
-
-/*
- * Generate the __enabled_CONFIG_* and __enabled_CONFIG_*_MODULE macros for
- * use by the IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is
- * generated even for booleans so that the IS_ENABLED() macro works.
- */
-static void
-header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE: {
- fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n",
- sym->name, (*value == 'y'));
- fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n",
- sym->name, (*value == 'm'));
- break;
- }
- default:
- break;
- }
-}
-
-static struct conf_printer header__enabled_printer_cb =
-{
- .print_symbol = header_print__enabled_symbol,
- .print_comment = header_print_comment,
-};
-
-/*
- * Tristate printer
- *
- * This printer is used when generating the `include/config/tristate.conf' file.
- */
-static void
-tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- if (sym->type == S_TRISTATE && *value != 'n')
- fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
-}
-
-static struct conf_printer tristate_printer_cb =
-{
- .print_symbol = tristate_print_symbol,
- .print_comment = kconfig_print_comment,
-};
-
-static void conf_write_symbol(FILE *fp, struct symbol *sym,
- struct conf_printer *printer, void *printer_arg)
-{
- const char *str;
-
- switch (sym->type) {
- case S_OTHER:
- case S_UNKNOWN:
- break;
- case S_STRING:
- str = sym_get_string_value(sym);
- str = sym_escape_string_value(str);
- printer->print_symbol(fp, sym, str, printer_arg);
- free((void *)str);
- break;
- default:
- str = sym_get_string_value(sym);
- printer->print_symbol(fp, sym, str, printer_arg);
- }
-}
-
-static void
-conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
-{
- char buf[256];
-
- snprintf(buf, sizeof(buf),
- "\n"
- "Automatically generated file; DO NOT EDIT.\n"
- "%s\n",
- rootmenu.prompt->text);
-
- printer->print_comment(fp, buf, printer_arg);
-}
-
-/*
- * 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();
-
- /* Traverse all menus to find all relevant symbols */
- menu = rootmenu.list;
-
- while (menu != NULL)
- {
- sym = menu->sym;
- if (sym == NULL) {
- if (!menu_is_visible(menu))
- goto next_menu;
- } else if (!sym_is_choice(sym)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next_menu;
- sym->flags &= ~SYMBOL_WRITE;
- /* If we cannot change the symbol - skip */
- if (!sym_is_changable(sym))
- goto next_menu;
- /* If symbol equals to default value - skip */
- if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
- goto next_menu;
-
- /*
- * If symbol is a choice value and equals to the
- * default for a choice - skip.
- * But only if value is bool and equal to "y" and
- * choice is not "optional".
- * (If choice is "optional" then all values can be "n")
- */
- if (sym_is_choice_value(sym)) {
- struct symbol *cs;
- struct symbol *ds;
-
- cs = prop_get_symbol(sym_get_choice_prop(sym));
- ds = sym_choice_default(cs);
- if (!sym_is_optional(cs) && sym == ds) {
- if ((sym->type == S_BOOLEAN) &&
- sym_get_tristate_value(sym) == yes)
- goto next_menu;
- }
- }
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
- }
-next_menu:
- if (menu->list != NULL) {
- menu = menu->list;
- }
- else if (menu->next != NULL) {
- menu = menu->next;
- } else {
- while ((menu = menu->parent)) {
- if (menu->next != NULL) {
- menu = menu->next;
- break;
- }
- }
- }
- }
- fclose(out);
- return 0;
-}
-
-int conf_write(const char *name)
-{
- FILE *out;
- struct symbol *sym;
- struct menu *menu;
- const char *basename;
- const char *str;
- char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
- char *env;
-
- dirname[0] = 0;
- if (name && name[0]) {
- struct stat st;
- char *slash;
-
- if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
- strcpy(dirname, name);
- strcat(dirname, "/");
- basename = conf_get_configname();
- } else if ((slash = strrchr(name, '/'))) {
- int size = slash - name + 1;
- memcpy(dirname, name, size);
- dirname[size] = 0;
- if (slash[1])
- basename = slash + 1;
- else
- basename = conf_get_configname();
- } else
- basename = name;
- } else
- basename = conf_get_configname();
-
- sprintf(newname, "%s%s", dirname, basename);
- env = getenv("KCONFIG_OVERWRITECONFIG");
- if (!env || !*env) {
- sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
- out = fopen(tmpname, "w");
- } else {
- *tmpname = 0;
- out = fopen(newname, "w");
- }
- if (!out)
- return 1;
-
- conf_write_heading(out, &kconfig_printer_cb, NULL);
-
- 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);
- } else if (!(sym->flags & SYMBOL_CHOICE)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next;
- sym->flags &= ~SYMBOL_WRITE;
-
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
- }
-
-next:
- if (menu->list) {
- menu = menu->list;
- continue;
- }
- if (menu->next)
- menu = menu->next;
- else while ((menu = menu->parent)) {
- if (menu->next) {
- menu = menu->next;
- break;
- }
- }
- }
- fclose(out);
-
- if (*tmpname) {
- strcat(dirname, basename);
- strcat(dirname, ".old");
- rename(newname, dirname);
- if (rename(tmpname, newname))
- return 1;
- }
-
- conf_message(_("configuration written to %s"), newname);
-
- sym_set_change_count(0);
-
- return 0;
-}
-
-static int conf_split_config(void)
-{
- const char *name;
- char path[PATH_MAX+1];
- char *s, *d, c;
- struct symbol *sym;
- struct stat sb;
- int res, i, fd;
-
- name = conf_get_autoconfig_name();
- conf_read_simple(name, S_DEF_AUTO);
-
- if (chdir("include/config"))
- return 1;
-
- res = 0;
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if ((sym->flags & SYMBOL_AUTO) || !sym->name)
- 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').
- */
-
- /* Replace all '_' and append ".h" */
- s = sym->name;
- d = path;
- while ((c = *s++)) {
- c = tolower(c);
- *d++ = (c == '_') ? '/' : c;
- }
- strcpy(d, ".h");
-
- /* Assume directory path already exists. */
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- if (errno != ENOENT) {
- res = 1;
- break;
- }
- /*
- * Create directory components,
- * unless they exist already.
- */
- d = path;
- while ((d = strchr(d, '/'))) {
- *d = 0;
- if (stat(path, &sb) && mkdir(path, 0755)) {
- res = 1;
- goto out;
- }
- *d++ = '/';
- }
- /* Try it again. */
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- res = 1;
- break;
- }
- }
- close(fd);
- }
-out:
- if (chdir("../.."))
- return 1;
-
- return res;
-}
-
-int conf_write_autoconf(void)
-{
- struct symbol *sym;
- const char *name;
- FILE *out, *tristate, *out_h;
- int i;
-
- sym_clear_all_valid();
-
- file_write_dep("include/config/auto.conf.cmd");
-
- if (conf_split_config())
- return 1;
-
- out = fopen(".tmpconfig", "w");
- if (!out)
- return 1;
-
- tristate = fopen(".tmpconfig_tristate", "w");
- if (!tristate) {
- fclose(out);
- return 1;
- }
-
- out_h = fopen(".tmpconfig.h", "w");
- if (!out_h) {
- fclose(out);
- fclose(tristate);
- return 1;
- }
-
- conf_write_heading(out, &kconfig_printer_cb, NULL);
-
- conf_write_heading(tristate, &tristate_printer_cb, NULL);
-
- conf_write_heading(out_h, &header_printer_cb, NULL);
-
- for_all_symbols(i, sym) {
- if (!sym->name)
- continue;
-
- sym_calc_value(sym);
-
- conf_write_symbol(out_h, sym, &header__enabled_printer_cb, NULL);
-
- if (!(sym->flags & SYMBOL_WRITE))
- continue;
-
- conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
-
- conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
-
- conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
- }
- fclose(out);
- fclose(tristate);
- fclose(out_h);
-
- name = getenv("KCONFIG_AUTOHEADER");
- if (!name)
- name = "include/generated/autoconf.h";
- if (rename(".tmpconfig.h", name))
- return 1;
- name = getenv("KCONFIG_TRISTATE");
- if (!name)
- name = "include/config/tristate.conf";
- if (rename(".tmpconfig_tristate", name))
- return 1;
- name = conf_get_autoconfig_name();
- /*
- * This must be the last step, kbuild has a dependency on auto.conf
- * and this marks the successful completion of the previous steps.
- */
- if (rename(".tmpconfig", name))
- return 1;
-
- return 0;
-}
-
-static int sym_change_count;
-static void (*conf_changed_callback)(void);
-
-void sym_set_change_count(int count)
-{
- int _sym_change_count = sym_change_count;
- sym_change_count = count;
- if (conf_changed_callback &&
- (bool)_sym_change_count != (bool)count)
- conf_changed_callback();
-}
-
-void sym_add_change_count(int count)
-{
- sym_set_change_count(count + sym_change_count);
-}
-
-bool conf_get_changed(void)
-{
- return sym_change_count;
-}
-
-void conf_set_changed_callback(void (*fn)(void))
-{
- conf_changed_callback = fn;
-}
-
-static void randomize_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
- int cnt, def;
-
- /*
- * If choice is mod then we may have more items selected
- * and if no then no-one.
- * In both cases stop.
- */
- if (csym->curr.tri != yes)
- return;
-
- prop = sym_get_choice_prop(csym);
-
- /* count entries in choice block */
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym)
- cnt++;
-
- /*
- * find a random value and set it to yes,
- * set the rest to no so we have only one set
- */
- def = (rand() % cnt);
-
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (def == cnt++) {
- sym->def[S_DEF_USER].tri = yes;
- csym->def[S_DEF_USER].val = sym;
- }
- else {
- sym->def[S_DEF_USER].tri = no;
- }
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID);
-}
-
-static void set_all_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
-
- prop = sym_get_choice_prop(csym);
-
- /*
- * Set all non-assinged choice values to no
- */
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (!sym_has_value(sym))
- sym->def[S_DEF_USER].tri = no;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID);
-}
-
-void conf_set_all_new_symbols(enum conf_def_mode mode)
-{
- struct symbol *sym, *csym;
- int i, cnt;
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym))
- continue;
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- switch (mode) {
- case def_yes:
- sym->def[S_DEF_USER].tri = yes;
- break;
- case def_mod:
- sym->def[S_DEF_USER].tri = mod;
- break;
- case def_no:
- sym->def[S_DEF_USER].tri = no;
- break;
- case def_random:
- cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
- sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
- break;
- default:
- continue;
- }
- if (!(sym_is_choice(sym) && mode == def_random))
- sym->flags |= SYMBOL_DEF_USER;
- break;
- default:
- break;
- }
-
- }
-
- sym_clear_all_valid();
-
- /*
- * We have different type of choice blocks.
- * If curr.tri equals to mod then we can select several
- * choice symbols in one block.
- * In this case we do nothing.
- * If curr.tri equals yes then only one symbol can be
- * selected in a choice block and we set it to yes,
- * and the rest to no.
- */
- for_all_symbols(i, csym) {
- if (sym_has_value(csym) || !sym_is_choice(csym))
- continue;
-
- sym_calc_value(csym);
- if (mode == def_random)
- randomize_choice_values(csym);
- else
- set_all_choice_values(csym);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "lkc.h"
-
-#define DEBUG_EXPR 0
-
-struct expr *expr_alloc_symbol(struct symbol *sym)
-{
- struct expr *e = calloc(1, sizeof(*e));
- e->type = E_SYMBOL;
- e->left.sym = sym;
- return e;
-}
-
-struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
-{
- struct expr *e = calloc(1, sizeof(*e));
- e->type = type;
- e->left.expr = ce;
- return e;
-}
-
-struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
-{
- struct expr *e = calloc(1, sizeof(*e));
- e->type = type;
- e->left.expr = e1;
- e->right.expr = e2;
- return e;
-}
-
-struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
-{
- struct expr *e = calloc(1, sizeof(*e));
- e->type = type;
- e->left.sym = s1;
- e->right.sym = s2;
- return e;
-}
-
-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;
-}
-
-struct expr *expr_copy(const struct expr *org)
-{
- struct expr *e;
-
- if (!org)
- return NULL;
-
- e = malloc(sizeof(*org));
- memcpy(e, org, sizeof(*org));
- switch (org->type) {
- case E_SYMBOL:
- e->left = org->left;
- break;
- case E_NOT:
- e->left.expr = expr_copy(org->left.expr);
- break;
- case E_EQUAL:
- case E_UNEQUAL:
- e->left.sym = org->left.sym;
- e->right.sym = org->right.sym;
- break;
- case E_AND:
- case E_OR:
- case E_LIST:
- e->left.expr = expr_copy(org->left.expr);
- e->right.expr = expr_copy(org->right.expr);
- break;
- default:
- printf("can't copy type %d\n", e->type);
- free(e);
- e = NULL;
- break;
- }
-
- return e;
-}
-
-void expr_free(struct expr *e)
-{
- if (!e)
- return;
-
- switch (e->type) {
- case E_SYMBOL:
- break;
- case E_NOT:
- expr_free(e->left.expr);
- return;
- case E_EQUAL:
- case E_UNEQUAL:
- break;
- case E_OR:
- case E_AND:
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- break;
- default:
- printf("how to free type %d?\n", e->type);
- break;
- }
- free(e);
-}
-
-static int trans_count;
-
-#define e1 (*ep1)
-#define e2 (*ep2)
-
-static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
-{
- if (e1->type == type) {
- __expr_eliminate_eq(type, &e1->left.expr, &e2);
- __expr_eliminate_eq(type, &e1->right.expr, &e2);
- return;
- }
- if (e2->type == type) {
- __expr_eliminate_eq(type, &e1, &e2->left.expr);
- __expr_eliminate_eq(type, &e1, &e2->right.expr);
- return;
- }
- if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
- e1->left.sym == e2->left.sym &&
- (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
- return;
- if (!expr_eq(e1, e2))
- return;
- trans_count++;
- expr_free(e1); expr_free(e2);
- switch (type) {
- case E_OR:
- e1 = expr_alloc_symbol(&symbol_no);
- e2 = expr_alloc_symbol(&symbol_no);
- break;
- case E_AND:
- e1 = expr_alloc_symbol(&symbol_yes);
- e2 = expr_alloc_symbol(&symbol_yes);
- break;
- default:
- ;
- }
-}
-
-void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
-{
- if (!e1 || !e2)
- return;
- switch (e1->type) {
- case E_OR:
- case E_AND:
- __expr_eliminate_eq(e1->type, ep1, ep2);
- default:
- ;
- }
- if (e1->type != e2->type) switch (e2->type) {
- case E_OR:
- case E_AND:
- __expr_eliminate_eq(e2->type, ep1, ep2);
- default:
- ;
- }
- e1 = expr_eliminate_yn(e1);
- e2 = expr_eliminate_yn(e2);
-}
-
-#undef e1
-#undef e2
-
-int expr_eq(struct expr *e1, struct expr *e2)
-{
- int res, old_count;
-
- if (e1->type != e2->type)
- return 0;
- switch (e1->type) {
- case E_EQUAL:
- 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:
- e1 = expr_copy(e1);
- e2 = expr_copy(e2);
- old_count = trans_count;
- expr_eliminate_eq(&e1, &e2);
- res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
- e1->left.sym == e2->left.sym);
- expr_free(e1);
- expr_free(e2);
- trans_count = old_count;
- return res;
- case E_LIST:
- case E_RANGE:
- case E_NONE:
- /* panic */;
- }
-
- if (DEBUG_EXPR) {
- expr_fprint(e1, stdout);
- printf(" = ");
- expr_fprint(e2, stdout);
- printf(" ?\n");
- }
-
- return 0;
-}
-
-struct expr *expr_eliminate_yn(struct expr *e)
-{
- struct expr *tmp;
-
- if (e) switch (e->type) {
- case E_AND:
- e->left.expr = expr_eliminate_yn(e->left.expr);
- e->right.expr = expr_eliminate_yn(e->right.expr);
- if (e->left.expr->type == E_SYMBOL) {
- if (e->left.expr->left.sym == &symbol_no) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.expr = NULL;
- return e;
- } else if (e->left.expr->left.sym == &symbol_yes) {
- free(e->left.expr);
- tmp = e->right.expr;
- *e = *(e->right.expr);
- free(tmp);
- return e;
- }
- }
- if (e->right.expr->type == E_SYMBOL) {
- if (e->right.expr->left.sym == &symbol_no) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.expr = NULL;
- return e;
- } else if (e->right.expr->left.sym == &symbol_yes) {
- free(e->right.expr);
- tmp = e->left.expr;
- *e = *(e->left.expr);
- free(tmp);
- return e;
- }
- }
- break;
- case E_OR:
- e->left.expr = expr_eliminate_yn(e->left.expr);
- e->right.expr = expr_eliminate_yn(e->right.expr);
- if (e->left.expr->type == E_SYMBOL) {
- if (e->left.expr->left.sym == &symbol_no) {
- free(e->left.expr);
- tmp = e->right.expr;
- *e = *(e->right.expr);
- free(tmp);
- return e;
- } else if (e->left.expr->left.sym == &symbol_yes) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.expr = NULL;
- return e;
- }
- }
- if (e->right.expr->type == E_SYMBOL) {
- if (e->right.expr->left.sym == &symbol_no) {
- free(e->right.expr);
- tmp = e->left.expr;
- *e = *(e->left.expr);
- free(tmp);
- return e;
- } else if (e->right.expr->left.sym == &symbol_yes) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.expr = NULL;
- return e;
- }
- }
- break;
- default:
- ;
- }
- return e;
-}
-
-/*
- * bool FOO!=n => FOO
- */
-struct expr *expr_trans_bool(struct expr *e)
-{
- if (!e)
- return NULL;
- switch (e->type) {
- case E_AND:
- case E_OR:
- case E_NOT:
- e->left.expr = expr_trans_bool(e->left.expr);
- e->right.expr = expr_trans_bool(e->right.expr);
- break;
- case E_UNEQUAL:
- // FOO!=n -> FOO
- if (e->left.sym->type == S_TRISTATE) {
- if (e->right.sym == &symbol_no) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
- }
- }
- 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 expr_copy(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 && sym1 == sym2) {
- 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 expr_copy(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;
-}
-
-static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
-{
-#define e1 (*ep1)
-#define e2 (*ep2)
- struct expr *tmp;
-
- if (e1->type == type) {
- expr_eliminate_dups1(type, &e1->left.expr, &e2);
- expr_eliminate_dups1(type, &e1->right.expr, &e2);
- return;
- }
- if (e2->type == type) {
- expr_eliminate_dups1(type, &e1, &e2->left.expr);
- expr_eliminate_dups1(type, &e1, &e2->right.expr);
- return;
- }
- if (e1 == e2)
- return;
-
- switch (e1->type) {
- case E_OR: case E_AND:
- expr_eliminate_dups1(e1->type, &e1, &e1);
- default:
- ;
- }
-
- switch (type) {
- case E_OR:
- tmp = expr_join_or(e1, e2);
- if (tmp) {
- expr_free(e1); expr_free(e2);
- e1 = expr_alloc_symbol(&symbol_no);
- e2 = tmp;
- trans_count++;
- }
- break;
- case E_AND:
- tmp = expr_join_and(e1, e2);
- if (tmp) {
- expr_free(e1); expr_free(e2);
- e1 = expr_alloc_symbol(&symbol_yes);
- e2 = tmp;
- trans_count++;
- }
- break;
- default:
- ;
- }
-#undef e1
-#undef e2
-}
-
-static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
-{
-#define e1 (*ep1)
-#define e2 (*ep2)
- struct expr *tmp, *tmp1, *tmp2;
-
- if (e1->type == type) {
- expr_eliminate_dups2(type, &e1->left.expr, &e2);
- expr_eliminate_dups2(type, &e1->right.expr, &e2);
- return;
- }
- if (e2->type == type) {
- expr_eliminate_dups2(type, &e1, &e2->left.expr);
- expr_eliminate_dups2(type, &e1, &e2->right.expr);
- }
- if (e1 == e2)
- return;
-
- switch (e1->type) {
- case E_OR:
- expr_eliminate_dups2(e1->type, &e1, &e1);
- // (FOO || BAR) && (!FOO && !BAR) -> n
- tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
- tmp2 = expr_copy(e2);
- tmp = expr_extract_eq_and(&tmp1, &tmp2);
- if (expr_is_yes(tmp1)) {
- expr_free(e1);
- e1 = expr_alloc_symbol(&symbol_no);
- trans_count++;
- }
- expr_free(tmp2);
- expr_free(tmp1);
- expr_free(tmp);
- break;
- case E_AND:
- expr_eliminate_dups2(e1->type, &e1, &e1);
- // (FOO && BAR) || (!FOO || !BAR) -> y
- tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
- tmp2 = expr_copy(e2);
- tmp = expr_extract_eq_or(&tmp1, &tmp2);
- if (expr_is_no(tmp1)) {
- expr_free(e1);
- e1 = expr_alloc_symbol(&symbol_yes);
- trans_count++;
- }
- expr_free(tmp2);
- expr_free(tmp1);
- expr_free(tmp);
- break;
- default:
- ;
- }
-#undef e1
-#undef e2
-}
-
-struct expr *expr_eliminate_dups(struct expr *e)
-{
- int oldcount;
- if (!e)
- return e;
-
- oldcount = trans_count;
- while (1) {
- trans_count = 0;
- switch (e->type) {
- case E_OR: case E_AND:
- expr_eliminate_dups1(e->type, &e, &e);
- expr_eliminate_dups2(e->type, &e, &e);
- default:
- ;
- }
- if (!trans_count)
- break;
- e = expr_eliminate_yn(e);
- }
- trans_count = oldcount;
- return e;
-}
-
-struct expr *expr_transform(struct expr *e)
-{
- struct expr *tmp;
-
- if (!e)
- return NULL;
- switch (e->type) {
- case E_EQUAL:
- case E_UNEQUAL:
- case E_SYMBOL:
- case E_LIST:
- break;
- default:
- e->left.expr = expr_transform(e->left.expr);
- e->right.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) {
- e->type = E_NOT;
- e->left.expr = expr_alloc_symbol(e->left.sym);
- e->right.sym = NULL;
- break;
- }
- if (e->right.sym == &symbol_mod) {
- printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.sym = NULL;
- break;
- }
- if (e->right.sym == &symbol_yes) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
- break;
- }
- break;
- case E_UNEQUAL:
- if (e->left.sym->type != S_BOOLEAN)
- break;
- if (e->right.sym == &symbol_no) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
- break;
- }
- if (e->right.sym == &symbol_mod) {
- printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.sym = NULL;
- break;
- }
- if (e->right.sym == &symbol_yes) {
- e->type = E_NOT;
- e->left.expr = expr_alloc_symbol(e->left.sym);
- e->right.sym = NULL;
- break;
- }
- break;
- case E_NOT:
- switch (e->left.expr->type) {
- case E_NOT:
- // !!a -> a
- tmp = e->left.expr->left.expr;
- free(e->left.expr);
- free(e);
- e = tmp;
- e = expr_transform(e);
- break;
- case E_EQUAL:
- case E_UNEQUAL:
- // !a='x' -> a!='x'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
- break;
- case E_OR:
- // !(a || b) -> !a && !b
- tmp = e->left.expr;
- e->type = E_AND;
- e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
- tmp->type = E_NOT;
- tmp->right.expr = NULL;
- e = expr_transform(e);
- break;
- case E_AND:
- // !(a && b) -> !a || !b
- tmp = e->left.expr;
- e->type = E_OR;
- e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
- tmp->type = E_NOT;
- tmp->right.expr = NULL;
- e = expr_transform(e);
- break;
- case E_SYMBOL:
- if (e->left.expr->left.sym == &symbol_yes) {
- // !'y' -> 'n'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- break;
- }
- if (e->left.expr->left.sym == &symbol_mod) {
- // !'m' -> 'm'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_mod;
- break;
- }
- if (e->left.expr->left.sym == &symbol_no) {
- // !'n' -> 'y'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- break;
- }
- break;
- default:
- ;
- }
- break;
- default:
- ;
- }
- return e;
-}
-
-int expr_contains_symbol(struct expr *dep, struct symbol *sym)
-{
- if (!dep)
- return 0;
-
- 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_UNEQUAL:
- return dep->left.sym == sym ||
- dep->right.sym == sym;
- case E_NOT:
- return expr_contains_symbol(dep->left.expr, sym);
- default:
- ;
- }
- return 0;
-}
-
-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;
-}
-
-struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
-{
- struct expr *tmp = NULL;
- expr_extract_eq(E_AND, &tmp, ep1, ep2);
- if (tmp) {
- *ep1 = expr_eliminate_yn(*ep1);
- *ep2 = expr_eliminate_yn(*ep2);
- }
- return tmp;
-}
-
-struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
-{
- struct expr *tmp = NULL;
- expr_extract_eq(E_OR, &tmp, ep1, ep2);
- if (tmp) {
- *ep1 = expr_eliminate_yn(*ep1);
- *ep2 = expr_eliminate_yn(*ep2);
- }
- return tmp;
-}
-
-void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
-{
-#define e1 (*ep1)
-#define e2 (*ep2)
- if (e1->type == type) {
- expr_extract_eq(type, ep, &e1->left.expr, &e2);
- expr_extract_eq(type, ep, &e1->right.expr, &e2);
- return;
- }
- if (e2->type == type) {
- expr_extract_eq(type, ep, ep1, &e2->left.expr);
- expr_extract_eq(type, ep, ep1, &e2->right.expr);
- return;
- }
- if (expr_eq(e1, e2)) {
- *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
- expr_free(e2);
- if (type == E_AND) {
- e1 = expr_alloc_symbol(&symbol_yes);
- e2 = expr_alloc_symbol(&symbol_yes);
- } else if (type == E_OR) {
- e1 = expr_alloc_symbol(&symbol_no);
- e2 = expr_alloc_symbol(&symbol_no);
- }
- }
-#undef e1
-#undef e2
-}
-
-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_EQUAL:
- if (type == E_EQUAL) {
- if (sym == &symbol_yes)
- return expr_copy(e);
- if (sym == &symbol_mod)
- return expr_alloc_symbol(&symbol_no);
- if (sym == &symbol_no)
- return expr_alloc_one(E_NOT, expr_copy(e));
- } else {
- if (sym == &symbol_yes)
- return expr_alloc_one(E_NOT, expr_copy(e));
- if (sym == &symbol_mod)
- return expr_alloc_symbol(&symbol_yes);
- if (sym == &symbol_no)
- return expr_copy(e);
- }
- break;
- case E_SYMBOL:
- return expr_alloc_comp(type, e->left.sym, sym);
- case E_LIST:
- case E_RANGE:
- case E_NONE:
- /* panic */;
- }
- return NULL;
-}
-
-tristate expr_calc_value(struct expr *e)
-{
- tristate val1, val2;
- const char *str1, *str2;
-
- if (!e)
- return yes;
-
- 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:
- 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);
- return !strcmp(str1, str2) ? yes : no;
- case E_UNEQUAL:
- 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);
- return !strcmp(str1, str2) ? no : yes;
- default:
- printf("expr_calc_value: %d?\n", e->type);
- return no;
- }
-}
-
-int expr_compare_type(enum expr_type t1, enum expr_type t2)
-{
-#if 0
- return 1;
-#else
- if (t1 == t2)
- return 0;
- switch (t1) {
- case E_EQUAL:
- case E_UNEQUAL:
- if (t2 == E_NOT)
- return 1;
- case E_NOT:
- if (t2 == E_AND)
- return 1;
- case E_AND:
- if (t2 == E_OR)
- return 1;
- case E_OR:
- if (t2 == E_LIST)
- return 1;
- case E_LIST:
- if (t2 == 0)
- return 1;
- default:
- return -1;
- }
- printf("[%dgt%d?]", t1, t2);
- return 0;
-#endif
-}
-
-static inline struct expr *
-expr_get_leftmost_symbol(const struct expr *e)
-{
-
- if (e == NULL)
- return NULL;
-
- while (e->type != E_SYMBOL)
- e = e->left.expr;
-
- return expr_copy(e);
-}
-
-/*
- * Given expression `e1' and `e2', returns the leaf of the longest
- * sub-expression of `e1' not containing 'e2.
- */
-struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
-{
- struct expr *ret;
-
- switch (e1->type) {
- case E_OR:
- return expr_alloc_and(
- expr_simplify_unmet_dep(e1->left.expr, e2),
- expr_simplify_unmet_dep(e1->right.expr, e2));
- case E_AND: {
- struct expr *e;
- e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
- e = expr_eliminate_dups(e);
- ret = (!expr_eq(e, e1)) ? e1 : NULL;
- expr_free(e);
- break;
- }
- default:
- ret = e1;
- break;
- }
-
- return expr_get_leftmost_symbol(ret);
-}
-
-void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
-{
- 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_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_LIST:
- fn(data, e->right.sym, e->right.sym->name);
- if (e->left.expr) {
- fn(data, NULL, " ^ ");
- expr_print(e->left.expr, fn, data, E_LIST);
- }
- 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(struct expr *e, struct gstr *gs)
-{
- expr_print(e, expr_print_gstr_helper, gs, E_NONE);
-}
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#ifndef EXPR_H
-#define EXPR_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-struct file {
- struct file *next;
- struct file *parent;
- const char *name;
- int lineno;
-};
-
-typedef enum tristate {
- no, mod, yes
-} tristate;
-
-enum expr_type {
- E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
-};
-
-union expr_data {
- struct expr *expr;
- struct symbol *sym;
-};
-
-struct expr {
- enum expr_type type;
- 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))
-
-#define expr_list_for_each_sym(l, e, s) \
- for (e = (l); e && (s = e->right.sym); e = e->left.expr)
-
-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, S_OTHER
-};
-
-/* 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
-};
-
-struct symbol {
- struct symbol *next;
- char *name;
- enum symbol_type type;
- struct symbol_value curr;
- struct symbol_value def[S_DEF_COUNT];
- tristate visible;
- int flags;
- struct property *prop;
- struct expr_value dir_dep;
- struct expr_value rev_dep;
-};
-
-#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
-
-#define SYMBOL_CONST 0x0001 /* symbol is const */
-#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
-#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
-#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
-#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
-#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
-#define SYMBOL_WRITE 0x0200 /* ? */
-#define SYMBOL_CHANGED 0x0400 /* ? */
-#define SYMBOL_AUTO 0x1000 /* value from environment variable */
-#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
-#define SYMBOL_HASHSIZE 9973
-
-/* 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
- */
-enum prop_type {
- P_UNKNOWN,
- P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
- P_COMMENT, /* text associated with a comment */
- P_MENU, /* prompt associated with a menuconfig option */
- P_DEFAULT, /* default y */
- P_CHOICE, /* choice value */
- P_SELECT, /* select BAR */
- P_RANGE, /* range 7..100 (for a symbol) */
- P_ENV, /* value from environment variable */
- P_SYMBOL, /* where a symbol is defined */
-};
-
-struct property {
- struct property *next; /* next property - null if last */
- struct symbol *sym; /* the symbol for which the property is associated */
- 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_CHOICE,
- * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
- struct file *file; /* 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_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
-#define for_all_prompts(sym, st) \
- for (st = sym->prop; st; st = st->next) \
- if (st->text)
-
-struct menu {
- struct menu *next;
- struct menu *parent;
- struct menu *list;
- struct symbol *sym;
- struct property *prompt;
- struct expr *visibility;
- struct expr *dep;
- unsigned int flags;
- char *help;
- struct file *file;
- int lineno;
- void *data;
-};
-
-#define MENU_CHANGED 0x0001
-#define MENU_ROOT 0x0002
-
-extern struct file *file_list;
-extern struct file *current_file;
-struct file *lookup_file(const char *name);
-
-extern struct symbol symbol_yes, symbol_no, symbol_mod;
-extern struct symbol *modules_sym;
-extern struct symbol *sym_defconfig_list;
-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);
-struct expr *expr_copy(const struct expr *org);
-void expr_free(struct expr *e);
-int expr_eq(struct expr *e1, struct expr *e2);
-void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
-tristate expr_calc_value(struct expr *e);
-struct expr *expr_eliminate_yn(struct expr *e);
-struct expr *expr_trans_bool(struct expr *e);
-struct expr *expr_eliminate_dups(struct expr *e);
-struct expr *expr_transform(struct expr *e);
-int expr_contains_symbol(struct expr *dep, struct symbol *sym);
-bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
-struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
-struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
-void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
-struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
-struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
-
-void expr_fprint(struct expr *e, FILE *out);
-struct gstr; /* forward */
-void expr_gstr_print(struct expr *e, struct gstr *gs);
-
-static inline int expr_is_yes(struct expr *e)
-{
- return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
-}
-
-static inline int expr_is_no(struct expr *e)
-{
- return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EXPR_H */
+++ /dev/null
-%language=ANSI-C
-%define hash-function-name kconf_id_hash
-%define lookup-function-name kconf_id_lookup
-%define string-pool-name kconf_id_strings
-%compare-strncmp
-%enum
-%pic
-%struct-type
-
-struct kconf_id;
-
-static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
-
-%%
-mainmenu, T_MAINMENU, TF_COMMAND
-menu, T_MENU, TF_COMMAND
-endmenu, T_ENDMENU, TF_COMMAND
-source, T_SOURCE, TF_COMMAND
-choice, T_CHOICE, TF_COMMAND
-endchoice, T_ENDCHOICE, TF_COMMAND
-comment, T_COMMENT, TF_COMMAND
-config, T_CONFIG, TF_COMMAND
-menuconfig, T_MENUCONFIG, TF_COMMAND
-help, T_HELP, TF_COMMAND
-if, T_IF, TF_COMMAND|TF_PARAM
-endif, T_ENDIF, TF_COMMAND
-depends, T_DEPENDS, TF_COMMAND
-optional, T_OPTIONAL, TF_COMMAND
-default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
-prompt, T_PROMPT, TF_COMMAND
-tristate, T_TYPE, TF_COMMAND, S_TRISTATE
-def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
-bool, T_TYPE, TF_COMMAND, S_BOOLEAN
-boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
-def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
-int, T_TYPE, TF_COMMAND, S_INT
-hex, T_TYPE, TF_COMMAND, S_HEX
-string, T_TYPE, TF_COMMAND, S_STRING
-select, T_SELECT, TF_COMMAND
-range, T_RANGE, TF_COMMAND
-visible, T_VISIBLE, TF_COMMAND
-option, T_OPTION, TF_COMMAND
-on, T_ON, TF_PARAM
-modules, T_OPT_MODULES, TF_OPTION
-defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
-env, T_OPT_ENV, TF_OPTION
-%%
+++ /dev/null
-%option nostdinit noyywrap never-interactive full ecs
-%option 8bit nodefault perf-report perf-report
-%option noinput
-%x COMMAND HELP STRING PARAM
-%{
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "lkc.h"
-
-#define START_STRSIZE 16
-
-static struct {
- struct file *file;
- int lineno;
-} current_pos;
-
-static char *text;
-static int text_size, text_asize;
-
-struct buffer {
- struct buffer *parent;
- YY_BUFFER_STATE state;
-};
-
-struct buffer *current_buf;
-
-static int last_ts, first_ts;
-
-static void zconf_endhelp(void);
-static void zconf_endfile(void);
-
-static void new_string(void)
-{
- text = malloc(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 = realloc(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 = malloc(size + 1);
- memcpy(text, str, size);
- text[size] = 0;
-}
-%}
-
-ws [ \n\t]
-n [A-Za-z0-9_]
-
-%%
- int str = 0;
- int ts, i;
-
-[ \t]*#.*\n |
-[ \t]*\n {
- current_file->lineno++;
- return T_EOL;
-}
-[ \t]*#.*
-
-
-[ \t]+ {
- BEGIN(COMMAND);
-}
-
-. {
- unput(yytext[0]);
- BEGIN(COMMAND);
-}
-
-
-<COMMAND>{
- {n}+ {
- const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
- BEGIN(PARAM);
- current_pos.file = current_file;
- current_pos.lineno = current_file->lineno;
- if (id && id->flags & TF_COMMAND) {
- zconflval.id = id;
- return id->token;
- }
- alloc_string(yytext, yyleng);
- zconflval.string = text;
- return T_WORD;
- }
- .
- \n {
- BEGIN(INITIAL);
- current_file->lineno++;
- return T_EOL;
- }
-}
-
-<PARAM>{
- "&&" return T_AND;
- "||" return T_OR;
- "(" return T_OPEN_PAREN;
- ")" return T_CLOSE_PAREN;
- "!" return T_NOT;
- "=" return T_EQUAL;
- "!=" return T_UNEQUAL;
- \"|\' {
- str = yytext[0];
- new_string();
- BEGIN(STRING);
- }
- \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
- --- /* ignore */
- ({n}|[-/.])+ {
- const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
- if (id && id->flags & TF_PARAM) {
- zconflval.id = id;
- return id->token;
- }
- alloc_string(yytext, yyleng);
- zconflval.string = text;
- return T_WORD;
- }
- #.* /* comment */
- \\\n current_file->lineno++;
- .
- <<EOF>> {
- BEGIN(INITIAL);
- }
-}
-
-<STRING>{
- [^'"\\\n]+/\n {
- append_string(yytext, yyleng);
- zconflval.string = text;
- return T_WORD_QUOTE;
- }
- [^'"\\\n]+ {
- append_string(yytext, yyleng);
- }
- \\.?/\n {
- append_string(yytext + 1, yyleng - 1);
- zconflval.string = text;
- return T_WORD_QUOTE;
- }
- \\.? {
- append_string(yytext + 1, yyleng - 1);
- }
- \'|\" {
- if (str == yytext[0]) {
- BEGIN(PARAM);
- zconflval.string = text;
- return T_WORD_QUOTE;
- } else
- append_string(yytext, 1);
- }
- \n {
- printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
- current_file->lineno++;
- BEGIN(INITIAL);
- return T_EOL;
- }
- <<EOF>> {
- BEGIN(INITIAL);
- }
-}
-
-<HELP>{
- [ \t]+ {
- 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] {
- current_file->lineno++;
- zconf_endhelp();
- return T_HELPTEXT;
- }
- [ \t]*\n {
- current_file->lineno++;
- 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>> {
- if (current_file) {
- zconf_endfile();
- return T_EOL;
- }
- fclose(yyin);
- yyterminate();
-}
-
-%%
-void zconf_starthelp(void)
-{
- new_string();
- last_ts = first_ts = 0;
- BEGIN(HELP);
-}
-
-static void zconf_endhelp(void)
-{
- zconflval.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) {
- sprintf(fullname, "%s/%s", env, name);
- f = fopen(fullname, "r");
- }
- }
- return f;
-}
-
-void zconf_initscan(const char *name)
-{
- yyin = zconf_fopen(name);
- if (!yyin) {
- printf("can't find file %s\n", name);
- exit(1);
- }
-
- current_buf = malloc(sizeof(*current_buf));
- memset(current_buf, 0, sizeof(*current_buf));
-
- current_file = file_lookup(name);
- current_file->lineno = 1;
-}
-
-void zconf_nextfile(const char *name)
-{
- struct file *iter;
- struct file *file = file_lookup(name);
- struct buffer *buf = malloc(sizeof(*buf));
- memset(buf, 0, sizeof(*buf));
-
- current_buf->state = YY_CURRENT_BUFFER;
- yyin = zconf_fopen(file->name);
- if (!yyin) {
- printf("%s:%d: can't open file \"%s\"\n",
- zconf_curname(), zconf_lineno(), file->name);
- exit(1);
- }
- yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- buf->parent = current_buf;
- current_buf = buf;
-
- for (iter = current_file->parent; iter; iter = iter->parent ) {
- if (!strcmp(current_file->name,iter->name) ) {
- printf("%s:%d: recursive inclusion detected. "
- "Inclusion path:\n current file : '%s'\n",
- zconf_curname(), zconf_lineno(),
- zconf_curname());
- iter = current_file->parent;
- while (iter && \
- strcmp(iter->name,current_file->name)) {
- printf(" included from: '%s:%d'\n",
- iter->name, iter->lineno-1);
- iter = iter->parent;
- }
- if (iter)
- printf(" included from: '%s:%d'\n",
- iter->name, iter->lineno+1);
- exit(1);
- }
- }
- file->lineno = 1;
- file->parent = current_file;
- current_file = file;
-}
-
-static void zconf_endfile(void)
-{
- struct buffer *parent;
-
- current_file = current_file->parent;
-
- parent = current_buf->parent;
- if (parent) {
- fclose(yyin);
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(parent->state);
- }
- free(current_buf);
- current_buf = parent;
-}
-
-int zconf_lineno(void)
-{
- return current_pos.lineno;
-}
-
-const char *zconf_curname(void)
-{
- return current_pos.file ? current_pos.file->name : "<none>";
-}
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#ifndef LKC_H
-#define LKC_H
-
-#include "expr.h"
-
-#ifndef KBUILD_NO_NLS
-# include <libintl.h>
-#else
-static inline const char *gettext(const char *txt) { return txt; }
-static inline void textdomain(const char *domainname) {}
-static inline void bindtextdomain(const char *name, const char *dir) {}
-static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define P(name,type,arg) extern type name arg
-#include "lkc_proto.h"
-#undef P
-
-#define SRCTREE "srctree"
-
-#ifndef PACKAGE
-#define PACKAGE "linux"
-#endif
-
-#define LOCALEDIR "/usr/share/locale"
-
-#define _(text) gettext(text)
-#define N_(text) (text)
-
-#ifndef CONFIG_
-#define CONFIG_ "CONFIG_"
-#endif
-
-#define TF_COMMAND 0x0001
-#define TF_PARAM 0x0002
-#define TF_OPTION 0x0004
-
-enum conf_def_mode {
- def_default,
- def_yes,
- def_mod,
- def_no,
- def_random
-};
-
-#define T_OPT_MODULES 1
-#define T_OPT_DEFCONFIG_LIST 2
-#define T_OPT_ENV 3
-
-struct kconf_id {
- int name;
- int token;
- unsigned int flags;
- enum symbol_type stype;
-};
-
-extern int zconfdebug;
-
-int zconfparse(void);
-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);
-int zconf_lineno(void);
-const char *zconf_curname(void);
-
-/* confdata.c */
-const char *conf_get_configname(void);
-const char *conf_get_autoconfig_name(void);
-char *conf_get_default_confname(void);
-void sym_set_change_count(int count);
-void sym_add_change_count(int count);
-void conf_set_all_new_symbols(enum conf_def_mode mode);
-
-struct conf_printer {
- void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
- void (*print_comment)(FILE *, const char *, 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");
-}
-
-/* menu.c */
-void _menu_init(void);
-void menu_warn(struct menu *menu, const char *fmt, ...);
-struct menu *menu_add_menu(void);
-void menu_end_menu(void);
-void menu_add_entry(struct symbol *sym);
-void menu_end_entry(void);
-void menu_add_dep(struct expr *dep);
-void menu_add_visibility(struct expr *dep);
-struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
-struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
-void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
-void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
-void menu_add_option(int token, char *arg);
-void menu_finalize(struct menu *parent);
-void menu_set_type(int type);
-
-/* util.c */
-struct file *file_lookup(const char *name);
-int file_write_dep(const char *name);
-
-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);
-struct gstr str_assign(const char *s);
-void str_free(struct gstr *gs);
-void str_append(struct gstr *gs, const char *s);
-void str_printf(struct gstr *gs, const char *fmt, ...);
-const char *str_get(struct gstr *gs);
-
-/* symbol.c */
-extern struct expr *sym_env_list;
-
-void sym_init(void);
-void sym_clear_all_valid(void);
-void sym_set_all_changed(void);
-void sym_set_changed(struct symbol *sym);
-struct symbol *sym_choice_default(struct symbol *sym);
-const char *sym_get_string_default(struct symbol *sym);
-struct symbol *sym_check_deps(struct symbol *sym);
-struct property *prop_alloc(enum prop_type type, struct symbol *sym);
-struct symbol *prop_get_symbol(struct property *prop);
-struct property *sym_get_env_prop(struct symbol *sym);
-
-static inline tristate sym_get_tristate_value(struct symbol *sym)
-{
- return sym->curr.tri;
-}
-
-
-static inline struct symbol *sym_get_choice_value(struct symbol *sym)
-{
- return (struct symbol *)sym->curr.val;
-}
-
-static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
-{
- return sym_set_tristate_value(chval, yes);
-}
-
-static inline bool sym_is_choice(struct symbol *sym)
-{
- return sym->flags & SYMBOL_CHOICE ? true : false;
-}
-
-static inline bool sym_is_choice_value(struct symbol *sym)
-{
- return sym->flags & SYMBOL_CHOICEVAL ? true : false;
-}
-
-static inline bool sym_is_optional(struct symbol *sym)
-{
- return sym->flags & SYMBOL_OPTIONAL ? true : false;
-}
-
-static inline bool sym_has_value(struct symbol *sym)
-{
- return sym->flags & SYMBOL_DEF_USER ? true : false;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LKC_H */
+++ /dev/null
-#include <stdarg.h>
-
-/* confdata.c */
-P(conf_parse,void,(const char *name));
-P(conf_read,int,(const char *name));
-P(conf_read_simple,int,(const char *name, int));
-P(conf_write_defconfig,int,(const char *name));
-P(conf_write,int,(const char *name));
-P(conf_write_autoconf,int,(void));
-P(conf_get_changed,bool,(void));
-P(conf_set_changed_callback, void,(void (*fn)(void)));
-P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
-
-/* menu.c */
-P(rootmenu,struct menu,);
-
-P(menu_is_visible, bool, (struct menu *menu));
-P(menu_has_prompt, bool, (struct menu *menu));
-P(menu_get_prompt,const char *,(struct menu *menu));
-P(menu_get_root_menu,struct menu *,(struct menu *menu));
-P(menu_get_parent_menu,struct menu *,(struct menu *menu));
-P(menu_has_help,bool,(struct menu *menu));
-P(menu_get_help,const char *,(struct menu *menu));
-P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
-P(get_relations_str, struct gstr, (struct symbol **sym_arr));
-P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
-
-/* symbol.c */
-P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
-
-P(sym_lookup,struct symbol *,(const char *name, int flags));
-P(sym_find,struct symbol *,(const char *name));
-P(sym_expand_string_value,const char *,(const char *in));
-P(sym_escape_string_value, const char *,(const char *in));
-P(sym_re_search,struct symbol **,(const char *pattern));
-P(sym_type_name,const char *,(enum symbol_type type));
-P(sym_calc_value,void,(struct symbol *sym));
-P(sym_get_type,enum symbol_type,(struct symbol *sym));
-P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
-P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
-P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
-P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
-P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
-P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
-P(sym_is_changable,bool,(struct symbol *sym));
-P(sym_get_choice_prop,struct property *,(struct symbol *sym));
-P(sym_get_default_prop,struct property *,(struct symbol *sym));
-P(sym_get_string_value,const char *,(struct symbol *sym));
-
-P(prop_get_type_name,const char *,(enum prop_type type));
-
-/* expr.c */
-P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
-P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "lkc.h"
-
-static const char nohelp_text[] = "There is no help available for this option.";
-
-struct menu rootmenu;
-static struct menu **last_entry_ptr;
-
-struct file *file_list;
-struct file *current_file;
-
-void menu_warn(struct menu *menu, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-static void prop_warn(struct property *prop, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", prop->file->name, 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)
-{
- struct menu *menu;
-
- menu = malloc(sizeof(*menu));
- memset(menu, 0, sizeof(*menu));
- menu->sym = sym;
- menu->parent = current_menu;
- menu->file = current_file;
- menu->lineno = zconf_lineno();
-
- *last_entry_ptr = menu;
- last_entry_ptr = &menu->next;
- current_entry = menu;
- if (sym)
- menu_add_symbol(P_SYMBOL, sym, NULL);
-}
-
-void menu_end_entry(void)
-{
-}
-
-struct menu *menu_add_menu(void)
-{
- menu_end_entry();
- last_entry_ptr = ¤t_entry->list;
- return current_menu = current_entry;
-}
-
-void menu_end_menu(void)
-{
- last_entry_ptr = ¤t_menu->next;
- current_menu = current_menu->parent;
-}
-
-static struct expr *menu_check_dep(struct expr *e)
-{
- if (!e)
- return e;
-
- switch (e->type) {
- case E_NOT:
- e->left.expr = menu_check_dep(e->left.expr);
- break;
- case E_OR:
- case E_AND:
- e->left.expr = menu_check_dep(e->left.expr);
- e->right.expr = menu_check_dep(e->right.expr);
- 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, menu_check_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, "type of '%s' redefined from '%s' to '%s'",
- sym->name ? sym->name : "<choice>",
- sym_type_name(sym->type), sym_type_name(type));
-}
-
-struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
-{
- struct property *prop = prop_alloc(type, current_entry->sym);
-
- prop->menu = current_entry;
- prop->expr = expr;
- prop->visible.expr = menu_check_dep(dep);
-
- if (prompt) {
- if (isspace(*prompt)) {
- prop_warn(prop, "leading whitespace ignored");
- while (isspace(*prompt))
- prompt++;
- }
- if (current_entry->prompt && current_entry != &rootmenu)
- 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;
-}
-
-struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
-{
- return menu_add_prop(type, prompt, NULL, dep);
-}
-
-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, NULL, expr, dep);
-}
-
-void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
-{
- menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
-}
-
-void menu_add_option(int token, char *arg)
-{
- struct property *prop;
-
- switch (token) {
- case T_OPT_MODULES:
- prop = prop_alloc(P_DEFAULT, modules_sym);
- prop->expr = expr_alloc_symbol(current_entry->sym);
- break;
- case T_OPT_DEFCONFIG_LIST:
- if (!sym_defconfig_list)
- sym_defconfig_list = current_entry->sym;
- else if (sym_defconfig_list != current_entry->sym)
- zconf_error("trying to redefine defconfig symbol");
- break;
- case T_OPT_ENV:
- prop_add_env(arg);
- break;
- }
-}
-
-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;
- 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);
- }
- break;
- case P_SELECT:
- sym2 = prop_get_symbol(prop);
- if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
- prop_warn(prop,
- "config symbol '%s' uses select, but is "
- "not boolean or tristate", sym->name);
- else if (sym2->type != S_UNKNOWN &&
- sym2->type != S_BOOLEAN &&
- sym2->type != S_TRISTATE)
- prop_warn(prop,
- "'%s' has wrong type. 'select' only "
- "accept arguments of boolean and "
- "tristate type", sym2->name);
- 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:
- ;
- }
- }
-}
-
-void menu_finalize(struct menu *parent)
-{
- struct menu *menu, *last_menu;
- struct symbol *sym;
- struct property *prop;
- struct expr *parentdep, *basedep, *dep, *dep2, **ep;
-
- sym = parent->sym;
- if (parent->list) {
- if (sym && sym_is_choice(sym)) {
- if (sym->type == S_UNKNOWN) {
- /* find the first choice value to find out choice type */
- current_entry = parent;
- for (menu = parent->list; menu; menu = menu->next) {
- if (menu->sym && menu->sym->type != S_UNKNOWN) {
- menu_set_type(menu->sym->type);
- break;
- }
- }
- }
- /* set the type of the remaining choice values */
- for (menu = parent->list; menu; menu = menu->next) {
- current_entry = menu;
- if (menu->sym && menu->sym->type == S_UNKNOWN)
- menu_set_type(sym->type);
- }
- parentdep = expr_alloc_symbol(sym);
- } else if (parent->prompt)
- parentdep = parent->prompt->visible.expr;
- else
- parentdep = parent->dep;
-
- for (menu = parent->list; menu; menu = menu->next) {
- basedep = expr_transform(menu->dep);
- basedep = expr_alloc_and(expr_copy(parentdep), basedep);
- basedep = expr_eliminate_dups(basedep);
- menu->dep = basedep;
- if (menu->sym)
- prop = menu->sym->prop;
- else
- prop = menu->prompt;
- for (; prop; prop = prop->next) {
- if (prop->menu != menu)
- continue;
- dep = expr_transform(prop->visible.expr);
- dep = expr_alloc_and(expr_copy(basedep), dep);
- dep = expr_eliminate_dups(dep);
- if (menu->sym && menu->sym->type != S_TRISTATE)
- dep = expr_trans_bool(dep);
- prop->visible.expr = dep;
- 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), expr_copy(dep)));
- }
- }
- }
- for (menu = parent->list; menu; menu = menu->next)
- menu_finalize(menu);
- } else if (sym) {
- basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
- basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
- basedep = expr_eliminate_dups(expr_transform(basedep));
- 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))
- break;
- if (expr_depends_symbol(dep, sym))
- goto next;
- dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
- dep = expr_eliminate_dups(expr_transform(dep));
- dep2 = expr_copy(basedep);
- expr_eliminate_eq(&dep, &dep2);
- expr_free(dep);
- if (!expr_is_yes(dep2)) {
- expr_free(dep2);
- break;
- }
- expr_free(dep2);
- next:
- menu_finalize(menu);
- 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) {
- if (sym && sym_is_choice(sym) &&
- menu->sym && !sym_is_choice_value(menu->sym)) {
- current_entry = menu;
- menu->sym->flags |= SYMBOL_CHOICEVAL;
- if (!menu->prompt)
- menu_warn(menu, "choice value must have a prompt");
- for (prop = menu->sym->prop; prop; prop = prop->next) {
- if (prop->type == P_DEFAULT)
- prop_warn(prop, "defaults for choice "
- "values not supported");
- if (prop->menu == menu)
- continue;
- if (prop->type == P_PROMPT &&
- prop->menu->parent->sym != sym)
- prop_warn(prop, "choice value used outside its choice group");
- }
- /* Non-tristate choice values of tristate choices must
- * depend on the choice being set to Y. The choice
- * values' dependencies were propagated to their
- * properties above, so the change here must be re-
- * propagated.
- */
- if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
- basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
- menu->dep = expr_alloc_and(basedep, menu->dep);
- for (prop = menu->sym->prop; prop; prop = prop->next) {
- if (prop->menu != menu)
- continue;
- prop->visible.expr = expr_alloc_and(expr_copy(basedep),
- prop->visible.expr);
- }
- }
- menu_add_symbol(P_CHOICE, sym, NULL);
- prop = sym_get_choice_prop(sym);
- for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
- ;
- *ep = expr_alloc_one(E_LIST, NULL);
- (*ep)->right.sym = menu->sym;
- }
- 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");
-
- if (sym_is_choice(sym) && !parent->prompt)
- menu_warn(parent, "choice must have a prompt");
-
- /* Check properties connected to this symbol */
- sym_check_prop(sym);
- sym->flags |= SYMBOL_WARNED;
- }
-
- if (sym && !sym_is_optional(sym) && parent->prompt) {
- sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
- expr_alloc_and(parent->prompt->visible.expr,
- expr_alloc_symbol(&symbol_mod)));
- }
-}
-
-bool menu_has_prompt(struct menu *menu)
-{
- if (!menu->prompt)
- 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 no;
- }
-
- 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)) {
- if (sym)
- sym->flags |= SYMBOL_DEF_USER;
- return true;
- }
- }
-
- return false;
-}
-
-const char *menu_get_prompt(struct menu *menu)
-{
- if (menu->prompt)
- return menu->prompt->text;
- else if (menu->sym)
- return menu->sym->name;
- return NULL;
-}
-
-struct menu *menu_get_root_menu(struct menu *menu)
-{
- return &rootmenu;
-}
-
-struct menu *menu_get_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;
-}
-
-bool menu_has_help(struct menu *menu)
-{
- return menu->help != NULL;
-}
-
-const char *menu_get_help(struct menu *menu)
-{
- if (menu->help)
- return menu->help;
- else
- return "";
-}
-
-static void get_prompt_str(struct gstr *r, struct property *prop)
-{
- int i, j;
- struct menu *submenu[8], *menu;
-
- str_printf(r, _("Prompt: %s\n"), _(prop->text));
- str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
- prop->menu->lineno);
- if (!expr_is_yes(prop->visible.expr)) {
- str_append(r, _(" Depends on: "));
- expr_gstr_print(prop->visible.expr, r);
- str_append(r, "\n");
- }
- menu = prop->menu->parent;
- for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
- submenu[i++] = menu;
- if (i > 0) {
- str_printf(r, _(" Location:\n"));
- for (j = 4; --i >= 0; j += 2) {
- menu = submenu[i];
- str_printf(r, "%*c-> %s", j, ' ', _(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");
- }
- }
-}
-
-void get_symbol_str(struct gstr *r, struct symbol *sym)
-{
- bool hit;
- struct property *prop;
-
- 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");
- }
- }
- }
- for_all_prompts(sym, prop)
- get_prompt_str(r, prop);
- hit = false;
- for_all_properties(sym, prop, P_SELECT) {
- if (!hit) {
- str_append(r, " Selects: ");
- hit = true;
- } else
- str_printf(r, " && ");
- expr_gstr_print(prop->expr, r);
- }
- if (hit)
- str_append(r, "\n");
- if (sym->rev_dep.expr) {
- str_append(r, _(" Selected by: "));
- expr_gstr_print(sym->rev_dep.expr, r);
- str_append(r, "\n");
- }
- str_append(r, "\n\n");
-}
-
-struct gstr get_relations_str(struct symbol **sym_arr)
-{
- 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);
- 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_has_help(menu)) {
- if (sym->name)
- str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
- help_text = menu_get_help(menu);
- }
- str_printf(help, "%s\n", _(help_text));
- if (sym)
- get_symbol_str(help, sym);
-}
+++ /dev/null
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <regex.h>
-#include <sys/utsname.h>
-
-#include "lkc.h"
-
-struct symbol symbol_yes = {
- .name = "y",
- .curr = { "y", yes },
- .flags = SYMBOL_CONST|SYMBOL_VALID,
-}, symbol_mod = {
- .name = "m",
- .curr = { "m", mod },
- .flags = SYMBOL_CONST|SYMBOL_VALID,
-}, symbol_no = {
- .name = "n",
- .curr = { "n", no },
- .flags = SYMBOL_CONST|SYMBOL_VALID,
-}, symbol_empty = {
- .name = "",
- .curr = { "", no },
- .flags = SYMBOL_VALID,
-};
-
-struct symbol *sym_defconfig_list;
-struct symbol *modules_sym;
-tristate modules_val;
-
-struct expr *sym_env_list;
-
-static void sym_add_default(struct symbol *sym, const char *def)
-{
- struct property *prop = prop_alloc(P_DEFAULT, sym);
-
- prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
-}
-
-void sym_init(void)
-{
- struct symbol *sym;
- struct utsname uts;
- static bool inited = false;
-
- if (inited)
- return;
- inited = true;
-
- uname(&uts);
-
- sym = sym_lookup("UNAME_RELEASE", 0);
- sym->type = S_STRING;
- sym->flags |= SYMBOL_AUTO;
- sym_add_default(sym, uts.release);
-}
-
-enum symbol_type sym_get_type(struct symbol *sym)
-{
- enum symbol_type type = sym->type;
-
- if (type == S_TRISTATE) {
- if (sym_is_choice_value(sym) && sym->visible == yes)
- type = S_BOOLEAN;
- else if (modules_val == no)
- type = S_BOOLEAN;
- }
- return type;
-}
-
-const char *sym_type_name(enum symbol_type type)
-{
- switch (type) {
- case S_BOOLEAN:
- return "boolean";
- 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";
- case S_OTHER:
- break;
- }
- return "???";
-}
-
-struct property *sym_get_choice_prop(struct symbol *sym)
-{
- struct property *prop;
-
- for_all_choices(sym, prop)
- return prop;
- return NULL;
-}
-
-struct property *sym_get_env_prop(struct symbol *sym)
-{
- struct property *prop;
-
- for_all_properties(sym, prop, P_ENV)
- return prop;
- return NULL;
-}
-
-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;
-}
-
-static 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 int 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 strtol(sym->curr.val, NULL, base);
-}
-
-static void sym_validate_range(struct symbol *sym)
-{
- struct property *prop;
- int base, val, val2;
- char str[64];
-
- 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 = strtol(sym->curr.val, NULL, base);
- val2 = sym_get_range_val(prop->expr->left.sym, base);
- if (val >= val2) {
- val2 = sym_get_range_val(prop->expr->right.sym, base);
- if (val <= val2)
- return;
- }
- if (sym->type == S_INT)
- sprintf(str, "%d", val2);
- else
- sprintf(str, "0x%x", val2);
- sym->curr.val = strdup(str);
-}
-
-static void sym_calc_visibility(struct symbol *sym)
-{
- struct property *prop;
- tristate tri;
-
- /* 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)
- 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);
- }
-}
-
-/*
- * 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 symbol *sym)
-{
- struct symbol *def_sym;
- struct property *prop;
- struct expr *e;
-
- /* any of the defaults visible? */
- for_all_defaults(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 */
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, def_sym)
- if (def_sym->visible != no)
- return def_sym;
-
- /* failed to locate any defaults */
- return NULL;
-}
-
-static struct symbol *sym_calc_choice(struct symbol *sym)
-{
- struct symbol *def_sym;
- struct property *prop;
- struct expr *e;
-
- /* first calculate all choice values' visibilities */
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, def_sym)
- sym_calc_visibility(def_sym);
-
- /* is the user choice visible? */
- def_sym = sym->def[S_DEF_USER].val;
- if (def_sym && def_sym->visible != no)
- return def_sym;
-
- def_sym = sym_choice_default(sym);
-
- if (def_sym == NULL)
- /* no choice? reset tristate value */
- sym->curr.tri = no;
-
- return def_sym;
-}
-
-void sym_calc_value(struct symbol *sym)
-{
- struct symbol_value newval, oldval;
- struct property *prop;
- struct expr *e;
-
- if (!sym)
- return;
-
- if (sym->flags & SYMBOL_VALID)
- return;
- sym->flags |= SYMBOL_VALID;
-
- oldval = sym->curr;
-
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- newval = symbol_empty.curr;
- break;
- case S_BOOLEAN:
- case S_TRISTATE:
- newval = symbol_no.curr;
- break;
- default:
- sym->curr.val = sym->name;
- sym->curr.tri = no;
- return;
- }
- if (!sym_is_choice_value(sym))
- sym->flags &= ~SYMBOL_WRITE;
-
- sym_calc_visibility(sym);
-
- /* set default if recursively called */
- sym->curr = newval;
-
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym_is_choice_value(sym) && sym->visible == yes) {
- prop = sym_get_choice_prop(sym);
- newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
- } else {
- if (sym->visible != no) {
- /* if the symbol is visible use the user value
- * if available, otherwise try the default value
- */
- sym->flags |= SYMBOL_WRITE;
- if (sym_has_value(sym)) {
- newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
- sym->visible);
- 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) {
- sym->flags |= SYMBOL_WRITE;
- newval.tri = EXPR_AND(expr_calc_value(prop->expr),
- prop->visible.tri);
- }
- }
- calc_newval:
- if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
- struct expr *e;
- e = expr_simplify_unmet_dep(sym->rev_dep.expr,
- sym->dir_dep.expr);
- fprintf(stderr, "warning: (");
- expr_fprint(e, stderr);
- fprintf(stderr, ") selects %s which has unmet direct dependencies (",
- sym->name);
- expr_fprint(sym->dir_dep.expr, stderr);
- fprintf(stderr, ")\n");
- expr_free(e);
- }
- 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->flags |= SYMBOL_WRITE;
- if (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:
- ;
- }
-
- sym->curr = newval;
- if (sym_is_choice(sym) && newval.tri == yes)
- sym->curr.val = sym_calc_choice(sym);
- 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)) {
- struct symbol *choice_sym;
-
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, choice_sym) {
- if ((sym->flags & SYMBOL_WRITE) &&
- choice_sym->visible != no)
- choice_sym->flags |= SYMBOL_WRITE;
- if (sym->flags & SYMBOL_CHANGED)
- sym_set_changed(choice_sym);
- }
- }
-
- if (sym->flags & SYMBOL_AUTO)
- sym->flags &= ~SYMBOL_WRITE;
-}
-
-void sym_clear_all_valid(void)
-{
- struct symbol *sym;
- int i;
-
- for_all_symbols(i, sym)
- sym->flags &= ~SYMBOL_VALID;
- sym_add_change_count(1);
- if (modules_sym)
- sym_calc_value(modules_sym);
-}
-
-void sym_set_changed(struct symbol *sym)
-{
- struct property *prop;
-
- sym->flags |= SYMBOL_CHANGED;
- for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->menu)
- prop->menu->flags |= MENU_CHANGED;
- }
-}
-
-void sym_set_all_changed(void)
-{
- struct symbol *sym;
- int i;
-
- for_all_symbols(i, sym)
- sym_set_changed(sym);
-}
-
-bool sym_tristate_within_range(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;
- if (sym_is_choice_value(sym) && sym->visible == yes)
- return val == yes;
- 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 (oldval != val && !sym_tristate_within_range(sym, val))
- return false;
-
- if (!(sym->flags & SYMBOL_DEF_USER)) {
- sym->flags |= SYMBOL_DEF_USER;
- sym_set_changed(sym);
- }
- /*
- * setting a choice value also resets the new flag of the choice
- * symbol and all other choice values.
- */
- if (sym_is_choice_value(sym) && val == yes) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- struct property *prop;
- struct expr *e;
-
- cs->def[S_DEF_USER].val = sym;
- cs->flags |= SYMBOL_DEF_USER;
- prop = sym_get_choice_prop(cs);
- for (e = prop->expr; e; e = e->left.expr) {
- if (e->right.sym->visible != no)
- e->right.sym->flags |= SYMBOL_DEF_USER;
- }
- }
-
- sym->def[S_DEF_USER].tri = val;
- if (oldval != val)
- sym_clear_all_valid();
-
- return true;
-}
-
-tristate sym_toggle_tristate_value(struct symbol *sym)
-{
- tristate oldval, newval;
-
- 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;
- int 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 = strtol(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 = strtol(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 = malloc(size);
- *val++ = '0';
- *val++ = 'x';
- } else if (!oldval || strcmp(oldval, newval))
- sym->def[S_DEF_USER].val = val = malloc(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;
- str = symbol_empty.curr.val;
-
- /* 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;
-
- 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:
- case S_HEX:
- return str;
- case S_STRING:
- return str;
- case S_OTHER:
- case S_UNKNOWN:
- break;
- }
- return "";
-}
-
-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:
- sym_calc_value(modules_sym);
- return (modules_sym->curr.tri == no) ? "n" : "m";
- case yes:
- return "y";
- }
- break;
- default:
- ;
- }
- return (const char *)sym->curr.val;
-}
-
-bool sym_is_changable(struct symbol *sym)
-{
- return sym->visible > sym->rev_dep.tri;
-}
-
-static unsigned strhash(const char *s)
-{
- /* fnv32 hash */
- unsigned hash = 2166136261U;
- for (; *s; s++)
- hash = (hash ^ *s) * 0x01000193;
- return hash;
-}
-
-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 = strhash(name) % SYMBOL_HASHSIZE;
-
- for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (symbol->name &&
- !strcmp(symbol->name, name) &&
- (flags ? symbol->flags & flags
- : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
- return symbol;
- }
- new_name = strdup(name);
- } else {
- new_name = NULL;
- hash = 0;
- }
-
- symbol = malloc(sizeof(*symbol));
- memset(symbol, 0, sizeof(*symbol));
- symbol->name = new_name;
- symbol->type = S_UNKNOWN;
- symbol->flags |= flags;
-
- symbol->next = symbol_hash[hash];
- symbol_hash[hash] = symbol;
-
- 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 = strhash(name) % SYMBOL_HASHSIZE;
-
- for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (symbol->name &&
- !strcmp(symbol->name, name) &&
- !(symbol->flags & SYMBOL_CONST))
- break;
- }
-
- return symbol;
-}
-
-/*
- * Expand symbol's names embedded in the string given in argument. Symbols'
- * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
- * the empty string.
- */
-const char *sym_expand_string_value(const char *in)
-{
- const char *src;
- char *res;
- size_t reslen;
-
- reslen = strlen(in) + 1;
- res = malloc(reslen);
- res[0] = '\0';
-
- while ((src = strchr(in, '$'))) {
- char *p, name[SYMBOL_MAXLENGTH];
- const char *symval = "";
- struct symbol *sym;
- size_t newlen;
-
- strncat(res, in, src - in);
- src++;
-
- p = name;
- while (isalnum(*src) || *src == '_')
- *p++ = *src++;
- *p = '\0';
-
- sym = sym_find(name);
- if (sym != NULL) {
- sym_calc_value(sym);
- symval = sym_get_string_value(sym);
- }
-
- newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
- if (newlen > reslen) {
- reslen = newlen;
- res = realloc(res, reslen);
- }
-
- strcat(res, symval);
- in = src;
- }
- strcat(res, in);
-
- return res;
-}
-
-const char *sym_escape_string_value(const char *in)
-{
- const char *p;
- size_t reslen;
- char *res;
- size_t l;
-
- reslen = strlen(in) + strlen("\"\"") + 1;
-
- p = in;
- for (;;) {
- l = strcspn(p, "\"\\");
- p += l;
-
- if (p[0] == '\0')
- break;
-
- reslen++;
- p++;
- }
-
- res = malloc(reslen);
- res[0] = '\0';
-
- strcat(res, "\"");
-
- p = in;
- for (;;) {
- l = strcspn(p, "\"\\");
- strncat(res, p, l);
- p += l;
-
- if (p[0] == '\0')
- break;
-
- strcat(res, "\\");
- strncat(res, p++, 1);
- }
-
- strcat(res, "\"");
- return res;
-}
-
-struct symbol **sym_re_search(const char *pattern)
-{
- struct symbol *sym, **sym_arr = NULL;
- int i, cnt, size;
- regex_t re;
-
- cnt = size = 0;
- /* Skip if empty */
- if (strlen(pattern) == 0)
- return NULL;
- if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
- return NULL;
-
- for_all_symbols(i, sym) {
- if (sym->flags & SYMBOL_CONST || !sym->name)
- continue;
- if (regexec(&re, sym->name, 0, NULL, 0))
- continue;
- if (cnt + 1 >= size) {
- void *tmp = sym_arr;
- size += 16;
- sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
- if (!sym_arr) {
- free(tmp);
- return NULL;
- }
- }
- sym_calc_value(sym);
- sym_arr[cnt++] = sym;
- }
- if (sym_arr)
- sym_arr[cnt] = NULL;
- 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 inser() 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 *menu = NULL;
- struct property *prop;
- struct dep_stack cv_stack;
-
- if (sym_is_choice_value(last_sym)) {
- dep_stack_insert(&cv_stack, last_sym);
- last_sym = prop_get_symbol(sym_get_choice_prop(last_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;
- prop = stack->prop;
- if (prop == NULL)
- prop = stack->sym->prop;
-
- /* for choice values find the menu entry (used below) */
- if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
- for (prop = sym->prop; prop; prop = prop->next) {
- menu = prop->menu;
- if (prop->menu)
- break;
- }
- }
- if (stack->sym == last_sym)
- fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
- prop->file->name, prop->lineno);
- if (stack->expr) {
- fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
- prop->file->name, prop->lineno,
- sym->name ? sym->name : "<choice>",
- prop_get_type_name(prop->type),
- next_sym->name ? next_sym->name : "<choice>");
- } else if (stack->prop) {
- fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
- prop->file->name, prop->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
- } else if (sym_is_choice(sym)) {
- fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
- menu->file->name, menu->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
- } else if (sym_is_choice_value(sym)) {
- fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
- menu->file->name, menu->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
- } else {
- fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
- prop->file->name, prop->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
- }
- }
-
- if (check_top == &cv_stack)
- dep_stack_remove();
-}
-
-static struct symbol *sym_check_expr_deps(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_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;
- }
- printf("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);
-
- sym2 = sym_check_expr_deps(sym->rev_dep.expr);
- if (sym2)
- goto out;
-
- for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->type == P_CHOICE || prop->type == P_SELECT)
- 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 symbol *sym, *sym2;
- struct property *prop;
- struct expr *e;
- struct dep_stack stack;
-
- dep_stack_insert(&stack, choice);
-
- prop = sym_get_choice_prop(choice);
- expr_list_for_each_sym(prop->expr, e, sym)
- 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;
-
- expr_list_for_each_sym(prop->expr, e, sym) {
- sym2 = sym_check_sym_deps(sym);
- if (sym2)
- break;
- }
-out:
- expr_list_for_each_sym(prop->expr, e, sym)
- sym->flags &= ~SYMBOL_CHECK;
-
- if (sym2 && sym_is_choice_value(sym2) &&
- prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
- sym2 = choice;
-
- dep_stack_remove();
-
- return sym2;
-}
-
-struct symbol *sym_check_deps(struct symbol *sym)
-{
- struct symbol *sym2;
- struct property *prop;
-
- if (sym->flags & SYMBOL_CHECK) {
- sym_check_print_recursive(sym);
- return sym;
- }
- if (sym->flags & SYMBOL_CHECKED)
- return NULL;
-
- if (sym_is_choice_value(sym)) {
- struct dep_stack stack;
-
- /* for choice groups start the check with main choice symbol */
- dep_stack_insert(&stack, sym);
- prop = sym_get_choice_prop(sym);
- sym2 = sym_check_deps(prop_get_symbol(prop));
- 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;
- }
-
- if (sym2 && sym2 == sym)
- sym2 = NULL;
-
- return sym2;
-}
-
-struct property *prop_alloc(enum prop_type type, struct symbol *sym)
-{
- struct property *prop;
- struct property **propp;
-
- prop = malloc(sizeof(*prop));
- memset(prop, 0, sizeof(*prop));
- prop->type = type;
- prop->sym = sym;
- prop->file = current_file;
- prop->lineno = zconf_lineno();
-
- /* append property to the prop list of symbol */
- if (sym) {
- for (propp = &sym->prop; *propp; propp = &(*propp)->next)
- ;
- *propp = prop;
- }
-
- return prop;
-}
-
-struct symbol *prop_get_symbol(struct property *prop)
-{
- if (prop->expr && (prop->expr->type == E_SYMBOL ||
- prop->expr->type == E_LIST))
- 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_ENV:
- return "env";
- case P_COMMENT:
- return "comment";
- case P_MENU:
- return "menu";
- case P_DEFAULT:
- return "default";
- case P_CHOICE:
- return "choice";
- case P_SELECT:
- return "select";
- case P_RANGE:
- return "range";
- case P_SYMBOL:
- return "symbol";
- case P_UNKNOWN:
- break;
- }
- return "unknown";
-}
-
-static void prop_add_env(const char *env)
-{
- struct symbol *sym, *sym2;
- struct property *prop;
- char *p;
-
- sym = current_entry->sym;
- sym->flags |= SYMBOL_AUTO;
- for_all_properties(sym, prop, P_ENV) {
- sym2 = prop_get_symbol(prop);
- if (strcmp(sym2->name, env))
- menu_warn(current_entry, "redefining environment symbol from %s",
- sym2->name);
- return;
- }
-
- prop = prop_alloc(P_ENV, sym);
- prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
-
- sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
- sym_env_list->right.sym = sym;
-
- p = getenv(env);
- if (p)
- sym_add_default(sym, p);
- else
- menu_warn(current_entry, "environment variable %s undefined", env);
-}
+++ /dev/null
-/*
- * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
- * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include "lkc.h"
-
-/* file already present in list? If not add it */
-struct file *file_lookup(const char *name)
-{
- struct file *file;
- const char *file_name = sym_expand_string_value(name);
-
- for (file = file_list; file; file = file->next) {
- if (!strcmp(name, file->name)) {
- free((void *)file_name);
- return file;
- }
- }
-
- file = malloc(sizeof(*file));
- memset(file, 0, sizeof(*file));
- file->name = file_name;
- file->next = file_list;
- file_list = file;
- return file;
-}
-
-/* write a dependency file as used by kbuild to track dependencies */
-int file_write_dep(const char *name)
-{
- struct symbol *sym, *env_sym;
- struct expr *e;
- struct file *file;
- FILE *out;
-
- if (!name)
- name = ".kconfig.d";
- out = fopen("..config.tmp", "w");
- if (!out)
- return 1;
- fprintf(out, "deps_config := \\\n");
- for (file = file_list; file; file = file->next) {
- if (file->next)
- fprintf(out, "\t%s \\\n", file->name);
- else
- fprintf(out, "\t%s\n", file->name);
- }
- fprintf(out, "\n%s: \\\n"
- "\t$(deps_config)\n\n", conf_get_autoconfig_name());
-
- expr_list_for_each_sym(sym_env_list, e, sym) {
- struct property *prop;
- const char *value;
-
- prop = sym_get_env_prop(sym);
- env_sym = prop_get_symbol(prop);
- if (!env_sym)
- continue;
- value = getenv(env_sym->name);
- if (!value)
- value = "";
- fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
- fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
- fprintf(out, "endif\n");
- }
-
- fprintf(out, "\n$(deps_config): ;\n");
- fclose(out);
- rename("..config.tmp", name);
- return 0;
-}
-
-
-/* Allocate initial growable string */
-struct gstr str_new(void)
-{
- struct gstr gs;
- gs.s = malloc(sizeof(char) * 64);
- gs.len = 64;
- gs.max_width = 0;
- strcpy(gs.s, "\0");
- return gs;
-}
-
-/* Allocate and assign growable string */
-struct gstr str_assign(const char *s)
-{
- struct gstr gs;
- gs.s = strdup(s);
- gs.len = strlen(s) + 1;
- gs.max_width = 0;
- return gs;
-}
-
-/* Free storage for growable string */
-void str_free(struct gstr *gs)
-{
- if (gs->s)
- 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 = realloc(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 */
-const char *str_get(struct gstr *gs)
-{
- return gs->s;
-}
-
+++ /dev/null
-%{
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include "lkc.h"
-
-#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
-
-#define PRINTD 0x0001
-#define DEBUG_PARSE 0x0002
-
-int cdebug = PRINTD;
-
-extern int zconflex(void);
-static void zconfprint(const char *err, ...);
-static void zconf_error(const char *err, ...);
-static void zconferror(const char *err);
-static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
-
-struct symbol *symbol_hash[SYMBOL_HASHSIZE];
-
-static struct menu *current_menu, *current_entry;
-
-%}
-%expect 30
-
-%union
-{
- char *string;
- struct file *file;
- struct symbol *symbol;
- struct expr *expr;
- struct menu *menu;
- const struct kconf_id *id;
-}
-
-%token <id>T_MAINMENU
-%token <id>T_MENU
-%token <id>T_ENDMENU
-%token <id>T_SOURCE
-%token <id>T_CHOICE
-%token <id>T_ENDCHOICE
-%token <id>T_COMMENT
-%token <id>T_CONFIG
-%token <id>T_MENUCONFIG
-%token <id>T_HELP
-%token <string> T_HELPTEXT
-%token <id>T_IF
-%token <id>T_ENDIF
-%token <id>T_DEPENDS
-%token <id>T_OPTIONAL
-%token <id>T_PROMPT
-%token <id>T_TYPE
-%token <id>T_DEFAULT
-%token <id>T_SELECT
-%token <id>T_RANGE
-%token <id>T_VISIBLE
-%token <id>T_OPTION
-%token <id>T_ON
-%token <string> T_WORD
-%token <string> T_WORD_QUOTE
-%token T_UNEQUAL
-%token T_CLOSE_PAREN
-%token T_OPEN_PAREN
-%token T_EOL
-
-%left T_OR
-%left T_AND
-%left T_EQUAL T_UNEQUAL
-%nonassoc T_NOT
-
-%type <string> prompt
-%type <symbol> symbol
-%type <expr> expr
-%type <expr> if_expr
-%type <id> end
-%type <id> option_name
-%type <menu> if_entry menu_entry choice_entry
-%type <string> symbol_option_arg word_opt
-
-%destructor {
- fprintf(stderr, "%s:%d: missing end statement for this entry\n",
- $$->file->name, $$->lineno);
- if (current_menu == $$)
- menu_end_menu();
-} if_entry menu_entry choice_entry
-
-%{
-/* Include zconf.hash.c here so it can see the token constants. */
-#include "hconf.c"
-%}
-
-%%
-input: nl start | start;
-
-start: mainmenu_stmt stmt_list | stmt_list;
-
-stmt_list:
- /* empty */
- | stmt_list common_stmt
- | stmt_list choice_stmt
- | stmt_list menu_stmt
- | stmt_list end { zconf_error("unexpected end statement"); }
- | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
- | stmt_list option_name error T_EOL
-{
- zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
-}
- | stmt_list error T_EOL { zconf_error("invalid statement"); }
-;
-
-option_name:
- T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
-;
-
-common_stmt:
- T_EOL
- | if_stmt
- | comment_stmt
- | config_stmt
- | menuconfig_stmt
- | source_stmt
-;
-
-option_error:
- T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
- | error T_EOL { zconf_error("invalid option"); }
-;
-
-
-/* config/menuconfig entry */
-
-config_entry_start: T_CONFIG T_WORD T_EOL
-{
- struct symbol *sym = sym_lookup($2, 0);
- sym->flags |= SYMBOL_OPTIONAL;
- menu_add_entry(sym);
- printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
-};
-
-config_stmt: config_entry_start config_option_list
-{
- menu_end_entry();
- printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-};
-
-menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
-{
- struct symbol *sym = sym_lookup($2, 0);
- sym->flags |= SYMBOL_OPTIONAL;
- menu_add_entry(sym);
- printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
-};
-
-menuconfig_stmt: menuconfig_entry_start config_option_list
-{
- if (current_entry->prompt)
- current_entry->prompt->type = P_MENU;
- else
- zconfprint("warning: menuconfig statement without prompt");
- menu_end_entry();
- printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-};
-
-config_option_list:
- /* empty */
- | config_option_list config_option
- | config_option_list symbol_option
- | config_option_list depends
- | config_option_list help
- | config_option_list option_error
- | config_option_list T_EOL
-;
-
-config_option: T_TYPE prompt_stmt_opt T_EOL
-{
- menu_set_type($1->stype);
- printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
- zconf_curname(), zconf_lineno(),
- $1->stype);
-};
-
-config_option: T_PROMPT prompt if_expr T_EOL
-{
- menu_add_prompt(P_PROMPT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_DEFAULT expr if_expr T_EOL
-{
- menu_add_expr(P_DEFAULT, $2, $3);
- if ($1->stype != S_UNKNOWN)
- menu_set_type($1->stype);
- printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
- zconf_curname(), zconf_lineno(),
- $1->stype);
-};
-
-config_option: T_SELECT T_WORD if_expr T_EOL
-{
- menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
- printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_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", zconf_curname(), zconf_lineno());
-};
-
-symbol_option: T_OPTION symbol_option_list T_EOL
-;
-
-symbol_option_list:
- /* empty */
- | symbol_option_list T_WORD symbol_option_arg
-{
- const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
- if (id && id->flags & TF_OPTION)
- menu_add_option(id->token, $3);
- else
- zconfprint("warning: ignoring unknown option %s", $2);
- free($2);
-};
-
-symbol_option_arg:
- /* empty */ { $$ = NULL; }
- | T_EQUAL prompt { $$ = $2; }
-;
-
-/* choice entry */
-
-choice: T_CHOICE word_opt T_EOL
-{
- struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
- sym->flags |= SYMBOL_AUTO;
- menu_add_entry(sym);
- menu_add_expr(P_CHOICE, NULL, NULL);
- printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
-};
-
-choice_entry: choice choice_option_list
-{
- $$ = menu_add_menu();
-};
-
-choice_end: end
-{
- if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
- menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
- }
-};
-
-choice_stmt: choice_entry choice_block choice_end
-;
-
-choice_option_list:
- /* empty */
- | choice_option_list choice_option
- | choice_option_list depends
- | choice_option_list help
- | choice_option_list T_EOL
- | choice_option_list option_error
-;
-
-choice_option: T_PROMPT prompt if_expr T_EOL
-{
- menu_add_prompt(P_PROMPT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-};
-
-choice_option: T_TYPE prompt_stmt_opt T_EOL
-{
- if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
- menu_set_type($1->stype);
- printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
- zconf_curname(), zconf_lineno(),
- $1->stype);
- } else
- YYERROR;
-};
-
-choice_option: T_OPTIONAL T_EOL
-{
- current_entry->sym->flags |= SYMBOL_OPTIONAL;
- printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
-};
-
-choice_option: T_DEFAULT T_WORD if_expr T_EOL
-{
- if ($1->stype == S_UNKNOWN) {
- menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
- printd(DEBUG_PARSE, "%s:%d:default\n",
- zconf_curname(), zconf_lineno());
- } else
- YYERROR;
-};
-
-choice_block:
- /* empty */
- | choice_block common_stmt
-;
-
-/* if entry */
-
-if_entry: T_IF expr nl
-{
- printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
- menu_add_entry(NULL);
- menu_add_dep($2);
- $$ = menu_add_menu();
-};
-
-if_end: end
-{
- if (zconf_endtoken($1, T_IF, T_ENDIF)) {
- menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
- }
-};
-
-if_stmt: if_entry if_block if_end
-;
-
-if_block:
- /* empty */
- | if_block common_stmt
- | if_block menu_stmt
- | if_block choice_stmt
-;
-
-/* mainmenu entry */
-
-mainmenu_stmt: T_MAINMENU prompt nl
-{
- menu_add_prompt(P_MENU, $2, NULL);
-};
-
-/* menu entry */
-
-menu: T_MENU prompt T_EOL
-{
- menu_add_entry(NULL);
- menu_add_prompt(P_MENU, $2, NULL);
- printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
-};
-
-menu_entry: menu visibility_list depends_list
-{
- $$ = menu_add_menu();
-};
-
-menu_end: end
-{
- if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
- menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
- }
-};
-
-menu_stmt: menu_entry menu_block menu_end
-;
-
-menu_block:
- /* empty */
- | menu_block common_stmt
- | menu_block menu_stmt
- | menu_block choice_stmt
-;
-
-source_stmt: T_SOURCE prompt T_EOL
-{
- printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
- zconf_nextfile($2);
-};
-
-/* comment entry */
-
-comment: T_COMMENT prompt T_EOL
-{
- menu_add_entry(NULL);
- menu_add_prompt(P_COMMENT, $2, NULL);
- printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
-};
-
-comment_stmt: comment depends_list
-{
- menu_end_entry();
-};
-
-/* help option */
-
-help_start: T_HELP T_EOL
-{
- printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
- zconf_starthelp();
-};
-
-help: help_start T_HELPTEXT
-{
- current_entry->help = $2;
-};
-
-/* depends option */
-
-depends_list:
- /* empty */
- | depends_list depends
- | depends_list T_EOL
- | depends_list option_error
-;
-
-depends: T_DEPENDS T_ON expr T_EOL
-{
- menu_add_dep($3);
- printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
-};
-
-/* visibility option */
-
-visibility_list:
- /* empty */
- | visibility_list visible
- | visibility_list T_EOL
-;
-
-visible: T_VISIBLE if_expr
-{
- menu_add_visibility($2);
-};
-
-/* prompt statement */
-
-prompt_stmt_opt:
- /* empty */
- | prompt if_expr
-{
- menu_add_prompt(P_PROMPT, $1, $2);
-};
-
-prompt: T_WORD
- | T_WORD_QUOTE
-;
-
-end: T_ENDMENU T_EOL { $$ = $1; }
- | T_ENDCHOICE T_EOL { $$ = $1; }
- | T_ENDIF T_EOL { $$ = $1; }
-;
-
-nl:
- T_EOL
- | nl T_EOL
-;
-
-if_expr: /* empty */ { $$ = NULL; }
- | T_IF expr { $$ = $2; }
-;
-
-expr: symbol { $$ = expr_alloc_symbol($1); }
- | 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); }
-;
-
-symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
- | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
-;
-
-word_opt: /* empty */ { $$ = NULL; }
- | T_WORD
-
-%%
-
-void conf_parse(const char *name)
-{
- struct symbol *sym;
- int i;
-
- zconf_initscan(name);
-
- sym_init();
- _menu_init();
- modules_sym = sym_lookup(NULL, 0);
- modules_sym->type = S_BOOLEAN;
- modules_sym->flags |= SYMBOL_AUTO;
- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
-
- if (getenv("ZCONF_DEBUG"))
- zconfdebug = 1;
- zconfparse();
- if (zconfnerrs)
- exit(1);
- if (!modules_sym->prop) {
- struct property *prop;
-
- prop = prop_alloc(P_DEFAULT, modules_sym);
- prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
- }
-
- rootmenu.prompt->text = _(rootmenu.prompt->text);
- rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
-
- menu_finalize(&rootmenu);
- for_all_symbols(i, sym) {
- if (sym_check_deps(sym))
- zconfnerrs++;
- }
- if (zconfnerrs)
- exit(1);
- sym_set_change_count(1);
-}
-
-static const char *zconf_tokenname(int token)
-{
- switch (token) {
- case T_MENU: return "menu";
- case T_ENDMENU: return "endmenu";
- case T_CHOICE: return "choice";
- case T_ENDCHOICE: return "endchoice";
- case T_IF: return "if";
- case T_ENDIF: return "endif";
- case T_DEPENDS: return "depends";
- case T_VISIBLE: return "visible";
- }
- return "<token>";
-}
-
-static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
-{
- if (id->token != endtoken) {
- zconf_error("unexpected '%s' within %s block",
- kconf_id_strings + id->name, zconf_tokenname(starttoken));
- zconfnerrs++;
- return false;
- }
- if (current_menu->file != current_file) {
- zconf_error("'%s' in different file than '%s'",
- kconf_id_strings + id->name, zconf_tokenname(starttoken));
- fprintf(stderr, "%s:%d: location of the '%s'\n",
- current_menu->file->name, current_menu->lineno,
- zconf_tokenname(starttoken));
- zconfnerrs++;
- return false;
- }
- return true;
-}
-
-static void zconfprint(const char *err, ...)
-{
- va_list ap;
-
- fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
- va_start(ap, err);
- vfprintf(stderr, err, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-}
-
-static void zconf_error(const char *err, ...)
-{
- va_list ap;
-
- zconfnerrs++;
- fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
- va_start(ap, err);
- vfprintf(stderr, err, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-}
-
-static void zconferror(const char *err)
-{
- fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, 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, 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(" boolean\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_CHOICE:
- fputs(" #choice value\n", out);
- break;
- case P_SELECT:
- fputs( " select ", 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;
- }
- }
- }
-}
-
-#include "lconf.c"
-#include "util.c"
-#include "confdata.c"
-#include "expr.c"
-#include "symbol.c"
-#include "menu.c"