2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
5 * Introduced single menu mode (show all sub-menus in one large tree).
6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
8 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
11 #include <sys/ioctl.h>
25 #define LKC_DIRECT_LINK
28 static char menu_backtitle[128];
29 static const char mconf_readme[] = N_(
32 "Some kernel features may be built directly into the kernel.\n"
33 "Some may be made into loadable runtime modules. Some features\n"
34 "may be completely removed altogether. There are also certain\n"
35 "kernel parameters which are not really features, but must be\n"
36 "entered in as decimal or hexadecimal numbers or possibly text.\n"
38 "Menu items beginning with [*], <M> or [ ] represent features\n"
39 "configured to be built in, modularized or removed respectively.\n"
40 "Pointed brackets <> represent module capable features.\n"
42 "To change any of these features, highlight it with the cursor\n"
43 "keys and press <Y> to build it in, <M> to make it a module or\n"
44 "<N> to removed it. You may also press the <Space Bar> to cycle\n"
45 "through the available options (ie. Y->N->M->Y).\n"
47 "Some additional keyboard hints:\n"
51 "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
52 " you wish to change or submenu wish to select and press <Enter>.\n"
53 " Submenus are designated by \"--->\".\n"
55 " Shortcut: Press the option's highlighted letter (hotkey).\n"
56 " Pressing a hotkey more than once will sequence\n"
57 " through all visible items which use that hotkey.\n"
59 " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
60 " unseen options into view.\n"
62 "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
63 " and press <ENTER>.\n"
65 " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
66 " using those letters. You may press a single <ESC>, but\n"
67 " there is a delayed response which you may find annoying.\n"
69 " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
70 " <Exit> and <Help>\n"
72 "o To get help with an item, use the cursor keys to highlight <Help>\n"
73 " and Press <ENTER>.\n"
75 " Shortcut: Press <H> or <?>.\n"
78 "Radiolists (Choice lists)\n"
80 "o Use the cursor keys to select the option you wish to set and press\n"
81 " <S> or the <SPACE BAR>.\n"
83 " Shortcut: Press the first letter of the option you wish to set then\n"
84 " press <S> or <SPACE BAR>.\n"
86 "o To see available help for the item, use the cursor keys to highlight\n"
87 " <Help> and Press <ENTER>.\n"
89 " Shortcut: Press <H> or <?>.\n"
91 " Also, the <TAB> and cursor keys will cycle between <Select> and\n"
97 "o Enter the requested information and press <ENTER>\n"
98 " If you are entering hexadecimal values, it is not necessary to\n"
99 " add the '0x' prefix to the entry.\n"
101 "o For help, use the <TAB> or cursor keys to highlight the help option\n"
102 " and press <ENTER>. You can try <TAB><H> as well.\n"
105 "Text Box (Help Window)\n"
107 "o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
108 " keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
109 " who are familiar with less and lynx.\n"
111 "o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
114 "Alternate Configuration Files\n"
115 "-----------------------------\n"
116 "Menuconfig supports the use of alternate configuration files for\n"
117 "those who, for various reasons, find it necessary to switch\n"
118 "between different kernel configurations.\n"
120 "At the end of the main menu you will find two options. One is\n"
121 "for saving the current configuration to a file of your choosing.\n"
122 "The other option is for loading a previously saved alternate\n"
125 "Even if you don't use alternate configuration files, but you\n"
126 "find during a Menuconfig session that you have completely messed\n"
127 "up your settings, you may use the \"Load Alternate...\" option to\n"
128 "restore your previously saved settings from \".config\" without\n"
129 "restarting Menuconfig.\n"
131 "Other information\n"
132 "-----------------\n"
133 "If you use Menuconfig in an XTERM window make sure you have your\n"
134 "$TERM variable set to point to a xterm definition which supports color.\n"
135 "Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
136 "display correctly in a RXVT window because rxvt displays only one\n"
137 "intensity of color, bright.\n"
139 "Menuconfig will display larger menus on screens or xterms which are\n"
140 "set to display more than the standard 25 row by 80 column geometry.\n"
141 "In order for this to work, the \"stty size\" command must be able to\n"
142 "display the screen's current row and column geometry. I STRONGLY\n"
143 "RECOMMEND that you make sure you do NOT have the shell variables\n"
144 "LINES and COLUMNS exported into your environment. Some distributions\n"
145 "export those variables via /etc/profile. Some ncurses programs can\n"
146 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
147 "the true screen size.\n"
149 "Optional personality available\n"
150 "------------------------------\n"
151 "If you prefer to have all of the kernel options listed in a single\n"
152 "menu, rather than the default multimenu hierarchy, run the menuconfig\n"
153 "with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
155 "make MENUCONFIG_MODE=single_menu menuconfig\n"
157 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
158 "is already unrolled.\n"
160 "Note that this mode can eventually be a little more CPU expensive\n"
161 "(especially with a larger number of unrolled categories) than the\n"
163 menu_instructions[] = N_(
164 "Arrow keys navigate the menu. "
165 "<Enter> selects submenus --->. "
166 "Highlighted letters are hotkeys. "
167 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
168 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
169 "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
170 radiolist_instructions[] = N_(
171 "Use the arrow keys to navigate this window or "
172 "press the hotkey of the item you wish to select "
173 "followed by the <SPACE BAR>. "
174 "Press <?> for additional information about this option."),
175 inputbox_instructions_int[] = N_(
176 "Please enter a decimal value. "
177 "Fractions will not be accepted. "
178 "Use the <TAB> key to move from the input field to the buttons below it."),
179 inputbox_instructions_hex[] = N_(
180 "Please enter a hexadecimal value. "
181 "Use the <TAB> key to move from the input field to the buttons below it."),
182 inputbox_instructions_string[] = N_(
183 "Please enter a string value. "
184 "Use the <TAB> key to move from the input field to the buttons below it."),
186 "This feature depends on another which has been configured as a module.\n"
187 "As a result, this feature will be built as a module."),
189 "There is no help available for this kernel option.\n"),
190 load_config_text[] = N_(
191 "Enter the name of the configuration file you wish to load. "
192 "Accept the name shown to restore the configuration you "
193 "last retrieved. Leave blank to abort."),
194 load_config_help[] = N_(
196 "For various reasons, one may wish to keep several different kernel\n"
197 "configurations available on a single machine.\n"
199 "If you have saved a previous configuration in a file other than the\n"
200 "kernel's default, entering the name of the file here will allow you\n"
201 "to modify that configuration.\n"
203 "If you are uncertain, then you have probably never used alternate\n"
204 "configuration files. You should therefor leave this blank to abort.\n"),
205 save_config_text[] = N_(
206 "Enter a filename to which this configuration should be saved "
207 "as an alternate. Leave blank to abort."),
208 save_config_help[] = N_(
210 "For various reasons, one may wish to keep different kernel\n"
211 "configurations available on a single machine.\n"
213 "Entering a file name here will allow you to later retrieve, modify\n"
214 "and use the current configuration as an alternate to whatever\n"
215 "configuration options you have selected at that time.\n"
217 "If you are uncertain what all this means then you should probably\n"
218 "leave this blank.\n"),
221 "Search for CONFIG_ symbols and display their relations.\n"
222 "Regular expressions are allowed.\n"
223 "Example: search for \"^FOO\"\n"
225 "-----------------------------------------------------------------\n"
227 "Prompt: Foo bus is used to drive the bar HW\n"
228 "Defined at drivers/pci/Kconfig:47\n"
229 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
231 " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
232 " -> PCI support (PCI [=y])\n"
233 " -> PCI access mode (<choice> [=y])\n"
234 "Selects: LIBCRC32\n"
236 "-----------------------------------------------------------------\n"
237 "o The line 'Prompt:' shows the text used in the menu structure for\n"
238 " this CONFIG_ symbol\n"
239 "o The 'Defined at' line tell at what file / line number the symbol\n"
241 "o The 'Depends on:' line tell what symbols needs to be defined for\n"
242 " this symbol to be visible in the menu (selectable)\n"
243 "o The 'Location:' lines tell where in the menu structure this symbol\n"
245 " A location followed by a [=y] indicate that this is a selectable\n"
246 " menu item - and current value is displayed inside brackets.\n"
247 "o The 'Selects:' line tell what symbol will be automatically\n"
248 " selected if this symbol is selected (y or m)\n"
249 "o The 'Selected by' line tell what symbol has selected this symbol\n"
251 "Only relevant lines are shown.\n"
254 "Examples: USB => find all CONFIG_ symbols containing USB\n"
255 " ^USB => find all CONFIG_ symbols starting with USB\n"
256 " USB$ => find all CONFIG_ symbols ending with USB\n"
259 static char buf[4096], *bufptr = buf;
260 static char input_buf[4096];
261 static char filename[PATH_MAX+1] = ".config";
262 static char *args[1024], **argptr = args;
264 static struct termios ios_org;
265 static int rows = 0, cols = 0;
266 static struct menu *current_menu;
267 static int child_count;
268 static int do_resize;
269 static int single_menu_mode;
271 static void conf(struct menu *menu);
272 static void conf_choice(struct menu *menu);
273 static void conf_string(struct menu *menu);
274 static void conf_load(void);
275 static void conf_save(void);
276 static void show_textbox(const char *title, const char *text, int r, int c);
277 static void show_helptext(const char *title, const char *text);
278 static void show_help(struct menu *menu);
279 static void show_file(const char *filename, const char *title, int r, int c);
281 static void cprint_init(void);
282 static int cprint1(const char *fmt, ...);
283 static void cprint_done(void);
284 static int cprint(const char *fmt, ...);
286 static void init_wsize(void)
291 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
297 env = getenv("LINES");
304 env = getenv("COLUMNS");
311 if (rows < 19 || cols < 80) {
312 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
313 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
321 static void cprint_init(void)
325 memset(args, 0, sizeof(args));
328 cprint("./scripts/kconfig/lxdialog/lxdialog");
329 cprint("--backtitle");
330 cprint(menu_backtitle);
333 static int cprint1(const char *fmt, ...)
341 res = vsprintf(bufptr, fmt, ap);
348 static void cprint_done(void)
354 static int cprint(const char *fmt, ...)
361 res = vsprintf(bufptr, fmt, ap);
369 static void get_prompt_str(struct gstr *r, struct property *prop)
372 struct menu *submenu[8], *menu;
374 str_printf(r, "Prompt: %s\n", prop->text);
375 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
377 if (!expr_is_yes(prop->visible.expr)) {
378 str_append(r, " Depends on: ");
379 expr_gstr_print(prop->visible.expr, r);
382 menu = prop->menu->parent;
383 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
386 str_printf(r, " Location:\n");
387 for (j = 4; --i >= 0; j += 2) {
389 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
391 str_printf(r, " (%s [=%s])", menu->sym->name ?
392 menu->sym->name : "<choice>",
393 sym_get_string_value(menu->sym));
400 static void get_symbol_str(struct gstr *r, struct symbol *sym)
403 struct property *prop;
405 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
406 sym_get_string_value(sym));
407 for_all_prompts(sym, prop)
408 get_prompt_str(r, prop);
410 for_all_properties(sym, prop, P_SELECT) {
412 str_append(r, " Selects: ");
415 str_printf(r, " && ");
416 expr_gstr_print(prop->expr, r);
420 if (sym->rev_dep.expr) {
421 str_append(r, " Selected by: ");
422 expr_gstr_print(sym->rev_dep.expr, r);
425 str_append(r, "\n\n");
428 static struct gstr get_relations_str(struct symbol **sym_arr)
431 struct gstr res = str_new();
434 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
435 get_symbol_str(&res, sym);
437 str_append(&res, "No matches found.\n");
443 static void winch_handler(int sig)
451 static int exec_conf(void)
453 int pipefd[2], stat, size;
455 sigset_t sset, osset;
458 sigaddset(&sset, SIGINT);
459 sigprocmask(SIG_BLOCK, &sset, &osset);
461 signal(SIGINT, SIG_DFL);
463 sa.sa_handler = winch_handler;
464 sigemptyset(&sa.sa_mask);
465 sa.sa_flags = SA_RESTART;
466 sigaction(SIGWINCH, &sa, NULL);
473 sigprocmask(SIG_SETMASK, &osset, NULL);
477 execv(args[0], args);
484 size = input_buf + sizeof(input_buf) - bufptr;
485 size = read(pipefd[0], bufptr, size);
488 if (errno == EINTR || errno == EAGAIN)
498 waitpid(pid, &stat, 0);
503 sigprocmask(SIG_SETMASK, &osset, NULL);
506 if (WIFSIGNALED(stat)) {
507 printf("\finterrupted(%d)\n", WTERMSIG(stat));
511 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
515 if (sigismember(&sset, SIGINT)) {
516 printf("\finterrupted\n");
519 sigprocmask(SIG_SETMASK, &osset, NULL);
521 return WEXITSTATUS(stat);
524 static void search_conf(void)
526 struct symbol **sym_arr;
533 cprint(_("Search Configuration Parameter"));
534 cprint("--inputbox");
535 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
546 show_helptext(_("Search Configuration"), search_help);
552 sym_arr = sym_re_search(input_buf);
553 res = get_relations_str(sym_arr);
555 show_textbox(_("Search Results"), str_get(&res), 0, 0);
559 static void build_conf(struct menu *menu)
562 struct property *prop;
564 int type, tmp, doint = 2;
568 if (!menu_is_visible(menu))
574 if (prop && menu != current_menu) {
575 const char *prompt = menu_get_prompt(menu);
576 switch (prop->type) {
581 if (single_menu_mode) {
583 menu->data ? "-->" : "++>",
584 indent + 1, ' ', prompt);
586 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
589 if (single_menu_mode && menu->data)
596 cprint("---%*c%s", indent + 1, ' ', prompt);
604 type = sym_get_type(sym);
605 if (sym_is_choice(sym)) {
606 struct symbol *def_sym = sym_get_choice_value(sym);
607 struct menu *def_menu = NULL;
610 for (child = menu->list; child; child = child->next) {
611 if (menu_is_visible(child) && child->sym == def_sym)
615 val = sym_get_tristate_value(sym);
616 if (sym_is_changable(sym)) {
620 cprint1("[%c]", val == no ? ' ' : '*');
624 case yes: ch = '*'; break;
625 case mod: ch = 'M'; break;
626 default: ch = ' '; break;
632 cprint("%c%p", def_menu ? 't' : ':', menu);
636 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
639 cprint1(" (%s)", menu_get_prompt(def_menu));
642 if (def_menu->list) {
644 build_conf(def_menu);
653 if (menu == current_menu) {
655 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
659 val = sym_get_tristate_value(sym);
660 if (sym_is_choice_value(sym) && val == yes) {
667 if (sym_is_changable(sym))
668 cprint1("[%c]", val == no ? ' ' : '*');
675 case yes: ch = '*'; break;
676 case mod: ch = 'M'; break;
677 default: ch = ' '; break;
679 if (sym_is_changable(sym))
686 tmp = cprint1("(%s)", sym_get_string_value(sym));
687 tmp = indent - tmp + 4;
690 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
691 (sym_has_value(sym) || !sym_is_changable(sym)) ?
697 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
698 (sym_has_value(sym) || !sym_is_changable(sym)) ?
700 if (menu->prompt->type == P_MENU) {
710 for (child = menu->list; child; child = child->next)
715 static void conf(struct menu *menu)
717 struct menu *submenu;
718 const char *prompt = menu_get_prompt(menu);
720 char active_entry[40];
723 unlink("lxdialog.scrltmp");
728 cprint("%s", prompt ? prompt : _("Main Menu"));
730 cprint(_(menu_instructions));
733 cprint("%d", rows - 10);
734 cprint("%s", active_entry);
739 if (menu == &rootmenu) {
743 cprint(_(" Load an Alternate Configuration File"));
745 cprint(_(" Save Configuration to an Alternate File"));
751 if (stat == 1 || stat == 255)
758 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
760 if (i >= sizeof(active_entry))
761 i = sizeof(active_entry) - 1;
763 strcpy(active_entry, input_buf);
767 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
774 if (single_menu_mode)
775 submenu->data = (void *) (long) !submenu->data;
780 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
781 conf_choice(submenu);
782 else if (submenu->prompt->type == P_MENU)
786 conf_string(submenu);
800 show_helptext("README", _(mconf_readme));
804 if (sym_set_tristate_value(sym, yes))
806 if (sym_set_tristate_value(sym, mod))
807 show_textbox(NULL, setmod_text, 6, 74);
812 sym_set_tristate_value(sym, no);
816 sym_set_tristate_value(sym, mod);
820 sym_toggle_tristate_value(sym);
821 else if (type == 'm')
831 static void show_textbox(const char *title, const char *text, int r, int c)
835 fd = creat(".help.tmp", 0777);
836 write(fd, text, strlen(text));
838 show_file(".help.tmp", title, r, c);
842 static void show_helptext(const char *title, const char *text)
844 show_textbox(title, text, 0, 0);
847 static void show_help(struct menu *menu)
849 struct gstr help = str_new();
850 struct symbol *sym = menu->sym;
855 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
856 str_append(&help, _(sym->help));
857 str_append(&help, "\n");
860 str_append(&help, nohelp_text);
862 get_symbol_str(&help, sym);
863 show_helptext(menu_get_prompt(menu), str_get(&help));
867 static void show_file(const char *filename, const char *title, int r, int c)
876 cprint("%s", filename);
877 cprint("%d", r ? r : rows);
878 cprint("%d", c ? c : cols);
879 } while (exec_conf() < 0);
882 static void conf_choice(struct menu *menu)
884 const char *prompt = menu_get_prompt(menu);
886 struct symbol *active;
889 active = sym_get_choice_value(menu->sym);
893 cprint("%s", prompt ? prompt : _("Main Menu"));
894 cprint("--radiolist");
895 cprint(_(radiolist_instructions));
901 for (child = menu->list; child; child = child->next) {
902 if (!menu_is_visible(child))
905 cprint("%s", menu_get_prompt(child));
906 if (child->sym == sym_get_choice_value(menu->sym))
908 else if (child->sym == active)
917 if (sscanf(input_buf, "%p", &child) != 1)
919 sym_set_tristate_value(child->sym, yes);
922 if (sscanf(input_buf, "%p", &child) == 1) {
934 static void conf_string(struct menu *menu)
936 const char *prompt = menu_get_prompt(menu);
942 cprint("%s", prompt ? prompt : _("Main Menu"));
943 cprint("--inputbox");
944 switch (sym_get_type(menu->sym)) {
946 cprint(_(inputbox_instructions_int));
949 cprint(_(inputbox_instructions_hex));
952 cprint(_(inputbox_instructions_string));
959 cprint("%s", sym_get_string_value(menu->sym));
963 if (sym_set_string_value(menu->sym, input_buf))
965 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
976 static void conf_load(void)
982 cprint("--inputbox");
983 cprint(load_config_text);
986 cprint("%s", filename);
992 if (!conf_read(input_buf))
994 show_textbox(NULL, _("File does not exist!"), 5, 38);
997 show_helptext(_("Load Alternate Configuration"), load_config_help);
1005 static void conf_save(void)
1011 cprint("--inputbox");
1012 cprint(save_config_text);
1015 cprint("%s", filename);
1021 if (!conf_write(input_buf))
1023 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1026 show_helptext(_("Save Alternate Configuration"), save_config_help);
1034 static void conf_cleanup(void)
1036 tcsetattr(1, TCSAFLUSH, &ios_org);
1037 unlink(".help.tmp");
1038 unlink("lxdialog.scrltmp");
1041 int main(int ac, char **av)
1047 setlocale(LC_ALL, "");
1048 bindtextdomain(PACKAGE, LOCALEDIR);
1049 textdomain(PACKAGE);
1054 sym = sym_lookup("KERNELRELEASE", 0);
1055 sym_calc_value(sym);
1056 sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
1057 sym_get_string_value(sym));
1059 mode = getenv("MENUCONFIG_MODE");
1061 if (!strcasecmp(mode, "single_menu"))
1062 single_menu_mode = 1;
1065 tcgetattr(1, &ios_org);
1066 atexit(conf_cleanup);
1073 cprint(_("Do you wish to save your new kernel configuration?"));
1080 if (conf_write(NULL)) {
1081 fprintf(stderr, _("\n\n"
1082 "Error during writing of the kernel configuration.\n"
1083 "Your kernel configuration changes were NOT saved."
1088 "*** End of Linux kernel configuration.\n"
1089 "*** Execute 'make' to build the kernel or try 'make help'."
1092 fprintf(stderr, _("\n\n"
1093 "Your kernel configuration changes were NOT saved."