From: Yann E. MORIN" Date: Fri, 20 Jan 2012 22:35:54 +0000 (+0100) Subject: misc: move the parser and the lxdialog to libs/ X-Git-Tag: v3.3.0-0~44 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=9e4343959cbc3a57a3e6a0ab7602d9482b15893d;p=kconfig-frontends misc: move the parser and the lxdialog to libs/ Signed-off-by: "Yann E. MORIN" --- diff --git a/.hgignore b/.hgignore index 696c0e3..ec7eb5d 100644 --- a/.hgignore +++ b/.hgignore @@ -9,7 +9,7 @@ frontends/gconf/gconf frontends/mconf/mconf frontends/nconf/nconf -parser/?conf.c +libs/parser/?conf.c aclocal.m4 configure @@ -20,8 +20,6 @@ config.status Makefile Makefile.in -lxdialog/Makefile -lxdialog/Makefile.in stamp-h1 .deps/ diff --git a/Makefile.am b/Makefile.am index 068a42b..aad98af 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS = lxdialog parser frontends +SUBDIRS = libs frontends diff --git a/configure.ac b/configure.ac index fd4563e..9b6bf39 100644 --- a/configure.ac +++ b/configure.ac @@ -143,8 +143,9 @@ AM_CONDITIONAL( # 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 diff --git a/frontends/conf/Makefile.am b/frontends/conf/Makefile.am index 72f9a7c..c8068df 100644 --- a/frontends/conf/Makefile.am +++ b/frontends/conf/Makefile.am @@ -3,5 +3,5 @@ bin_PROGRAMS = conf 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 diff --git a/frontends/gconf/Makefile.am b/frontends/gconf/Makefile.am index 76fbf26..3f34d6e 100644 --- a/frontends/gconf/Makefile.am +++ b/frontends/gconf/Makefile.am @@ -2,13 +2,13 @@ bin_PROGRAMS = gconf 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 diff --git a/frontends/mconf/Makefile.am b/frontends/mconf/Makefile.am index 7c784e2..4e06958 100644 --- a/frontends/mconf/Makefile.am +++ b/frontends/mconf/Makefile.am @@ -4,5 +4,7 @@ mconf_SOURCES = mconf.c 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 diff --git a/frontends/nconf/Makefile.am b/frontends/nconf/Makefile.am index f952e71..b439c83 100644 --- a/frontends/nconf/Makefile.am +++ b/frontends/nconf/Makefile.am @@ -1,7 +1,8 @@ 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 diff --git a/libs/Makefile.am b/libs/Makefile.am new file mode 100644 index 0000000..6e11169 --- /dev/null +++ b/libs/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = parser lxdialog diff --git a/libs/lxdialog/.gitignore b/libs/lxdialog/.gitignore new file mode 100644 index 0000000..90b08ff --- /dev/null +++ b/libs/lxdialog/.gitignore @@ -0,0 +1,4 @@ +# +# Generated files +# +lxdialog diff --git a/libs/lxdialog/BIG.FAT.WARNING b/libs/lxdialog/BIG.FAT.WARNING new file mode 100644 index 0000000..a8999d8 --- /dev/null +++ b/libs/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +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. diff --git a/libs/lxdialog/Makefile.am b/libs/lxdialog/Makefile.am new file mode 100644 index 0000000..5f22423 --- /dev/null +++ b/libs/lxdialog/Makefile.am @@ -0,0 +1,14 @@ +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) diff --git a/libs/lxdialog/checklist.c b/libs/lxdialog/checklist.c new file mode 100644 index 0000000..a2eb80f --- /dev/null +++ b/libs/lxdialog/checklist.c @@ -0,0 +1,332 @@ +/* + * 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 */ +} diff --git a/libs/lxdialog/dialog.h b/libs/lxdialog/dialog.h new file mode 100644 index 0000000..b5211fc --- /dev/null +++ b/libs/lxdialog/dialog.h @@ -0,0 +1,230 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#ifndef KBUILD_NO_NLS +# include +#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) diff --git a/libs/lxdialog/inputbox.c b/libs/lxdialog/inputbox.c new file mode 100644 index 0000000..dd8e587 --- /dev/null +++ b/libs/lxdialog/inputbox.c @@ -0,0 +1,238 @@ +/* + * 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 */ +} diff --git a/libs/lxdialog/menubox.c b/libs/lxdialog/menubox.c new file mode 100644 index 0000000..1d60473 --- /dev/null +++ b/libs/lxdialog/menubox.c @@ -0,0 +1,434 @@ +/* + * 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 */ +} diff --git a/libs/lxdialog/textbox.c b/libs/lxdialog/textbox.c new file mode 100644 index 0000000..154c2dd --- /dev/null +++ b/libs/lxdialog/textbox.c @@ -0,0 +1,390 @@ +/* + * 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); +} diff --git a/libs/lxdialog/util.c b/libs/lxdialog/util.c new file mode 100644 index 0000000..f2375ad --- /dev/null +++ b/libs/lxdialog/util.c @@ -0,0 +1,657 @@ +/* + * 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 + +#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 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); +} diff --git a/libs/lxdialog/yesno.c b/libs/lxdialog/yesno.c new file mode 100644 index 0000000..4e6e809 --- /dev/null +++ b/libs/lxdialog/yesno.c @@ -0,0 +1,114 @@ +/* + * 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 */ +} diff --git a/libs/parser/Makefile.am b/libs/parser/Makefile.am new file mode 100644 index 0000000..5f0d352 --- /dev/null +++ b/libs/parser/Makefile.am @@ -0,0 +1,35 @@ +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$@ $< diff --git a/libs/parser/confdata.c b/libs/parser/confdata.c new file mode 100644 index 0000000..7c7a5a6 --- /dev/null +++ b/libs/parser/confdata.c @@ -0,0 +1,1155 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} diff --git a/libs/parser/expr.c b/libs/parser/expr.c new file mode 100644 index 0000000..290ce41 --- /dev/null +++ b/libs/parser/expr.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#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, ""); + 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, ""); + 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, ""); + 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, "", 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); +} diff --git a/libs/parser/expr.h b/libs/parser/expr.h new file mode 100644 index 0000000..d4ecce8 --- /dev/null +++ b/libs/parser/expr.h @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifndef __cplusplus +#include +#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 */ diff --git a/libs/parser/hconf.gperf b/libs/parser/hconf.gperf new file mode 100644 index 0000000..f14ab41 --- /dev/null +++ b/libs/parser/hconf.gperf @@ -0,0 +1,47 @@ +%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 +%% diff --git a/libs/parser/lconf.l b/libs/parser/lconf.l new file mode 100644 index 0000000..00f9d3a --- /dev/null +++ b/libs/parser/lconf.l @@ -0,0 +1,364 @@ +%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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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); +} + + +{ + {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; + } +} + +{ + "&&" 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++; + . + <> { + BEGIN(INITIAL); + } +} + +{ + [^'"\\\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; + } + <> { + BEGIN(INITIAL); + } +} + +{ + [ \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; + } + <> { + zconf_endhelp(); + return T_HELPTEXT; + } +} + +<> { + 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 : ""; +} diff --git a/libs/parser/lkc.h b/libs/parser/lkc.h new file mode 100644 index 0000000..c18f2bd --- /dev/null +++ b/libs/parser/lkc.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#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 */ diff --git a/libs/parser/lkc_proto.h b/libs/parser/lkc_proto.h new file mode 100644 index 0000000..47fe9c3 --- /dev/null +++ b/libs/parser/lkc_proto.h @@ -0,0 +1,54 @@ +#include + +/* 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)); diff --git a/libs/parser/menu.c b/libs/parser/menu.c new file mode 100644 index 0000000..8c2a97e --- /dev/null +++ b/libs/parser/menu.c @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include + +#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 : "", + 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 : _(""), + 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); +} diff --git a/libs/parser/symbol.c b/libs/parser/symbol.c new file mode 100644 index 0000000..071f00c --- /dev/null +++ b/libs/parser/symbol.c @@ -0,0 +1,1303 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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 : "", + prop_get_type_name(prop->type), + next_sym->name ? next_sym->name : ""); + } else if (stack->prop) { + fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice(sym)) { + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice_value(sym)) { + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else { + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } + } + + 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); +} diff --git a/libs/parser/util.c b/libs/parser/util.c new file mode 100644 index 0000000..d0b8b23 --- /dev/null +++ b/libs/parser/util.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#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; +} + diff --git a/libs/parser/yconf.y b/libs/parser/yconf.y new file mode 100644 index 0000000..a09276e --- /dev/null +++ b/libs/parser/yconf.y @@ -0,0 +1,740 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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 T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_VISIBLE +%token T_OPTION +%token T_ON +%token T_WORD +%token 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 prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type 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 ""; +} + +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" diff --git a/lxdialog/.gitignore b/lxdialog/.gitignore deleted file mode 100644 index 90b08ff..0000000 --- a/lxdialog/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# -# Generated files -# -lxdialog diff --git a/lxdialog/BIG.FAT.WARNING b/lxdialog/BIG.FAT.WARNING deleted file mode 100644 index a8999d8..0000000 --- a/lxdialog/BIG.FAT.WARNING +++ /dev/null @@ -1,4 +0,0 @@ -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. diff --git a/lxdialog/Makefile.am b/lxdialog/Makefile.am deleted file mode 100644 index 5f22423..0000000 --- a/lxdialog/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -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) diff --git a/lxdialog/checklist.c b/lxdialog/checklist.c deleted file mode 100644 index a2eb80f..0000000 --- a/lxdialog/checklist.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * checklist.c -- implements the checklist box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension - * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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 */ -} diff --git a/lxdialog/dialog.h b/lxdialog/dialog.h deleted file mode 100644 index b5211fc..0000000 --- a/lxdialog/dialog.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include - -#ifndef KBUILD_NO_NLS -# include -#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) diff --git a/lxdialog/inputbox.c b/lxdialog/inputbox.c deleted file mode 100644 index dd8e587..0000000 --- a/lxdialog/inputbox.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * inputbox.c -- implements the input box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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 */ -} diff --git a/lxdialog/menubox.c b/lxdialog/menubox.c deleted file mode 100644 index 1d60473..0000000 --- a/lxdialog/menubox.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * menubox.c -- implements the menu box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) - * - * 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 */ -} diff --git a/lxdialog/textbox.c b/lxdialog/textbox.c deleted file mode 100644 index 154c2dd..0000000 --- a/lxdialog/textbox.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * textbox.c -- implements the text box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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); -} diff --git a/lxdialog/util.c b/lxdialog/util.c deleted file mode 100644 index f2375ad..0000000 --- a/lxdialog/util.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * 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 - -#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 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); -} diff --git a/lxdialog/yesno.c b/lxdialog/yesno.c deleted file mode 100644 index 4e6e809..0000000 --- a/lxdialog/yesno.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * yesno.c -- implements the yes/no box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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 */ -} diff --git a/parser/Makefile.am b/parser/Makefile.am deleted file mode 100644 index 5f0d352..0000000 --- a/parser/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -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$@ $< diff --git a/parser/confdata.c b/parser/confdata.c deleted file mode 100644 index 7c7a5a6..0000000 --- a/parser/confdata.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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); - } -} diff --git a/parser/expr.c b/parser/expr.c deleted file mode 100644 index 290ce41..0000000 --- a/parser/expr.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include - -#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, ""); - 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, ""); - 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, ""); - 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, "", 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); -} diff --git a/parser/expr.h b/parser/expr.h deleted file mode 100644 index d4ecce8..0000000 --- a/parser/expr.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef EXPR_H -#define EXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#ifndef __cplusplus -#include -#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 */ diff --git a/parser/hconf.gperf b/parser/hconf.gperf deleted file mode 100644 index f14ab41..0000000 --- a/parser/hconf.gperf +++ /dev/null @@ -1,47 +0,0 @@ -%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 -%% diff --git a/parser/lconf.l b/parser/lconf.l deleted file mode 100644 index 00f9d3a..0000000 --- a/parser/lconf.l +++ /dev/null @@ -1,364 +0,0 @@ -%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 - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include - -#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); -} - - -{ - {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; - } -} - -{ - "&&" 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++; - . - <> { - BEGIN(INITIAL); - } -} - -{ - [^'"\\\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; - } - <> { - BEGIN(INITIAL); - } -} - -{ - [ \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; - } - <> { - zconf_endhelp(); - return T_HELPTEXT; - } -} - -<> { - 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 : ""; -} diff --git a/parser/lkc.h b/parser/lkc.h deleted file mode 100644 index c18f2bd..0000000 --- a/parser/lkc.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef LKC_H -#define LKC_H - -#include "expr.h" - -#ifndef KBUILD_NO_NLS -# include -#else -static inline const char *gettext(const char *txt) { return txt; } -static inline void textdomain(const char *domainname) {} -static inline void bindtextdomain(const char *name, const char *dir) {} -static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#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 */ diff --git a/parser/lkc_proto.h b/parser/lkc_proto.h deleted file mode 100644 index 47fe9c3..0000000 --- a/parser/lkc_proto.h +++ /dev/null @@ -1,54 +0,0 @@ -#include - -/* 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)); diff --git a/parser/menu.c b/parser/menu.c deleted file mode 100644 index 8c2a97e..0000000 --- a/parser/menu.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include - -#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 : "", - 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 : _(""), - 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); -} diff --git a/parser/symbol.c b/parser/symbol.c deleted file mode 100644 index 071f00c..0000000 --- a/parser/symbol.c +++ /dev/null @@ -1,1303 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include - -#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 : "", - prop_get_type_name(prop->type), - next_sym->name ? next_sym->name : ""); - } else if (stack->prop) { - fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice(sym)) { - fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice_value(sym)) { - fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else { - fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } - } - - 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); -} diff --git a/parser/util.c b/parser/util.c deleted file mode 100644 index d0b8b23..0000000 --- a/parser/util.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2002-2005 Roman Zippel - * Copyright (C) 2002-2005 Sam Ravnborg - * - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#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; -} - diff --git a/parser/yconf.y b/parser/yconf.y deleted file mode 100644 index a09276e..0000000 --- a/parser/yconf.y +++ /dev/null @@ -1,740 +0,0 @@ -%{ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#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 T_MAINMENU -%token T_MENU -%token T_ENDMENU -%token T_SOURCE -%token T_CHOICE -%token T_ENDCHOICE -%token T_COMMENT -%token T_CONFIG -%token T_MENUCONFIG -%token T_HELP -%token T_HELPTEXT -%token T_IF -%token T_ENDIF -%token T_DEPENDS -%token T_OPTIONAL -%token T_PROMPT -%token T_TYPE -%token T_DEFAULT -%token T_SELECT -%token T_RANGE -%token T_VISIBLE -%token T_OPTION -%token T_ON -%token T_WORD -%token 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 prompt -%type symbol -%type expr -%type if_expr -%type end -%type option_name -%type if_entry menu_entry choice_entry -%type 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 ""; -} - -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"