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>
22 #define LKC_DIRECT_LINK
25 static char menu_backtitle[128];
26 static const char menu_instructions[] =
27 "Arrow keys navigate the menu. "
28 "<Enter> selects submenus --->. "
29 "Highlighted letters are hotkeys. "
30 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
31 "Press <Esc><Esc> to exit, <?> for Help. "
32 "Legend: [*] built-in [ ] excluded <M> module < > module capable",
33 radiolist_instructions[] =
34 "Use the arrow keys to navigate this window or "
35 "press the hotkey of the item you wish to select "
36 "followed by the <SPACE BAR>. "
37 "Press <?> for additional information about this option.",
38 inputbox_instructions_int[] =
39 "Please enter a decimal value. "
40 "Fractions will not be accepted. "
41 "Use the <TAB> key to move from the input field to the buttons below it.",
42 inputbox_instructions_hex[] =
43 "Please enter a hexadecimal value. "
44 "Use the <TAB> key to move from the input field to the buttons below it.",
45 inputbox_instructions_string[] =
46 "Please enter a string value. "
47 "Use the <TAB> key to move from the input field to the buttons below it.",
49 "This feature depends on another which has been configured as a module.\n"
50 "As a result, this feature will be built as a module.",
52 "There is no help available for this kernel option.\n",
54 "Enter the name of the configuration file you wish to load. "
55 "Accept the name shown to restore the configuration you "
56 "last retrieved. Leave blank to abort.",
59 "For various reasons, one may wish to keep several different kernel\n"
60 "configurations available on a single machine.\n"
62 "If you have saved a previous configuration in a file other than the\n"
63 "kernel's default, entering the name of the file here will allow you\n"
64 "to modify that configuration.\n"
66 "If you are uncertain, then you have probably never used alternate\n"
67 "configuration files. You should therefor leave this blank to abort.\n",
69 "Enter a filename to which this configuration should be saved "
70 "as an alternate. Leave blank to abort.",
73 "For various reasons, one may wish to keep different kernel\n"
74 "configurations available on a single machine.\n"
76 "Entering a file name here will allow you to later retrieve, modify\n"
77 "and use the current configuration as an alternate to whatever\n"
78 "configuration options you have selected at that time.\n"
80 "If you are uncertain what all this means then you should probably\n"
84 static char buf[4096], *bufptr = buf;
85 static char input_buf[4096];
86 static char filename[PATH_MAX+1] = ".config";
87 static char *args[1024], **argptr = args;
89 static struct termios ios_org;
90 static int rows, cols;
91 static struct menu *current_menu;
92 static int child_count;
94 static int single_menu_mode;
96 static void conf(struct menu *menu);
97 static void conf_choice(struct menu *menu);
98 static void conf_string(struct menu *menu);
99 static void conf_load(void);
100 static void conf_save(void);
101 static void show_textbox(const char *title, const char *text, int r, int c);
102 static void show_helptext(const char *title, const char *text);
103 static void show_help(struct menu *menu);
104 static void show_readme(void);
106 static void cprint_init(void);
107 static int cprint1(const char *fmt, ...);
108 static void cprint_done(void);
109 static int cprint(const char *fmt, ...);
111 static void init_wsize(void)
116 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
123 env = getenv("LINES");
130 env = getenv("COLUMNS");
138 if (rows < 19 || cols < 80) {
139 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
140 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
148 static void cprint_init(void)
152 memset(args, 0, sizeof(args));
155 cprint("./scripts/lxdialog/lxdialog");
156 cprint("--backtitle");
157 cprint(menu_backtitle);
160 static int cprint1(const char *fmt, ...)
168 res = vsprintf(bufptr, fmt, ap);
175 static void cprint_done(void)
181 static int cprint(const char *fmt, ...)
188 res = vsprintf(bufptr, fmt, ap);
198 static void winch_handler(int sig)
206 static int exec_conf(void)
208 int pipefd[2], stat, size;
210 sigset_t sset, osset;
213 sigaddset(&sset, SIGINT);
214 sigprocmask(SIG_BLOCK, &sset, &osset);
216 signal(SIGINT, SIG_DFL);
218 sa.sa_handler = winch_handler;
219 sigemptyset(&sa.sa_mask);
220 sa.sa_flags = SA_RESTART;
221 sigaction(SIGWINCH, &sa, NULL);
228 sigprocmask(SIG_SETMASK, &osset, NULL);
232 execv(args[0], args);
239 size = input_buf + sizeof(input_buf) - bufptr;
240 size = read(pipefd[0], bufptr, size);
243 if (errno == EINTR || errno == EAGAIN)
253 waitpid(pid, &stat, 0);
258 sigprocmask(SIG_SETMASK, &osset, NULL);
261 if (WIFSIGNALED(stat)) {
262 printf("\finterrupted(%d)\n", WTERMSIG(stat));
266 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
270 if (sigismember(&sset, SIGINT)) {
271 printf("\finterrupted\n");
274 sigprocmask(SIG_SETMASK, &osset, NULL);
276 return WEXITSTATUS(stat);
279 static void build_conf(struct menu *menu)
282 struct property *prop;
284 int type, tmp, doint = 2;
288 if (!menu_is_visible(menu))
294 if (prop && menu != current_menu) {
295 const char *prompt = menu_get_prompt(menu);
296 switch (prop->type) {
301 if (single_menu_mode) {
303 menu->data ? "-->" : "++>",
304 indent + 1, ' ', prompt);
306 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
309 if (single_menu_mode && menu->data)
316 cprint("---%*c%s", indent + 1, ' ', prompt);
324 type = sym_get_type(sym);
325 if (sym_is_choice(sym)) {
326 struct symbol *def_sym = sym_get_choice_value(sym);
327 struct menu *def_menu = NULL;
330 for (child = menu->list; child; child = child->next) {
331 if (menu_is_visible(child) && child->sym == def_sym)
335 val = sym_get_tristate_value(sym);
336 if (sym_is_changable(sym)) {
340 cprint1("[%c]", val == no ? ' ' : '*');
344 case yes: ch = '*'; break;
345 case mod: ch = 'M'; break;
346 default: ch = ' '; break;
352 cprint("%c%p", def_menu ? 't' : ':', menu);
356 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
359 cprint1(" (%s)", menu_get_prompt(def_menu));
362 if (def_menu->list) {
364 build_conf(def_menu);
373 if (menu == current_menu) {
375 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
379 val = sym_get_tristate_value(sym);
380 if (sym_is_choice_value(sym) && val == yes) {
387 if (sym_is_changable(sym))
388 cprint1("[%c]", val == no ? ' ' : '*');
395 case yes: ch = '*'; break;
396 case mod: ch = 'M'; break;
397 default: ch = ' '; break;
399 if (sym_is_changable(sym))
406 tmp = cprint1("(%s)", sym_get_string_value(sym));
407 tmp = indent - tmp + 4;
410 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
411 (sym_has_value(sym) || !sym_is_changable(sym)) ?
417 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
418 (sym_has_value(sym) || !sym_is_changable(sym)) ?
420 if (menu->prompt->type == P_MENU) {
430 for (child = menu->list; child; child = child->next)
435 static void conf(struct menu *menu)
437 struct menu *submenu;
438 const char *prompt = menu_get_prompt(menu);
440 char active_entry[40];
443 unlink("lxdialog.scrltmp");
448 cprint("%s", prompt ? prompt : "Main Menu");
450 cprint(menu_instructions);
453 cprint("%d", rows - 10);
454 cprint("%s", active_entry);
459 if (menu == &rootmenu) {
463 cprint(" Load an Alternate Configuration File");
465 cprint(" Save Configuration to an Alternate File");
471 if (stat == 1 || stat == 255)
478 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
480 if (i >= sizeof(active_entry))
481 i = sizeof(active_entry) - 1;
483 strcpy(active_entry, input_buf);
487 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
494 if (single_menu_mode)
495 submenu->data = (void *) (long) !submenu->data;
500 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
501 conf_choice(submenu);
502 else if (submenu->prompt->type == P_MENU)
506 conf_string(submenu);
524 if (sym_set_tristate_value(sym, yes))
526 if (sym_set_tristate_value(sym, mod))
527 show_textbox(NULL, setmod_text, 6, 74);
532 sym_set_tristate_value(sym, no);
536 sym_set_tristate_value(sym, mod);
540 sym_toggle_tristate_value(sym);
541 else if (type == 'm')
548 static void show_textbox(const char *title, const char *text, int r, int c)
552 fd = creat(".help.tmp", 0777);
553 write(fd, text, strlen(text));
565 } while (exec_conf() < 0);
569 static void show_helptext(const char *title, const char *text)
571 show_textbox(title, text, rows, cols);
574 static void show_help(struct menu *menu)
578 struct symbol *sym = menu->sym;
584 helptext = malloc(strlen(sym->name) + strlen(help) + 16);
585 sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help);
586 show_helptext(menu_get_prompt(menu), helptext);
589 show_helptext(menu_get_prompt(menu), help);
592 static void show_readme(void)
597 cprint("scripts/README.Menuconfig");
600 } while (exec_conf() == -1);
603 static void conf_choice(struct menu *menu)
605 const char *prompt = menu_get_prompt(menu);
607 struct symbol *active;
610 active = sym_get_choice_value(menu->sym);
614 cprint("%s", prompt ? prompt : "Main Menu");
615 cprint("--radiolist");
616 cprint(radiolist_instructions);
622 for (child = menu->list; child; child = child->next) {
623 if (!menu_is_visible(child))
626 cprint("%s", menu_get_prompt(child));
627 if (child->sym == sym_get_choice_value(menu->sym))
629 else if (child->sym == active)
638 if (sscanf(input_buf, "%p", &child) != 1)
640 sym_set_tristate_value(child->sym, yes);
643 if (sscanf(input_buf, "%p", &child) == 1) {
655 static void conf_string(struct menu *menu)
657 const char *prompt = menu_get_prompt(menu);
663 cprint("%s", prompt ? prompt : "Main Menu");
664 cprint("--inputbox");
665 switch (sym_get_type(menu->sym)) {
667 cprint(inputbox_instructions_int);
670 cprint(inputbox_instructions_hex);
673 cprint(inputbox_instructions_string);
680 cprint("%s", sym_get_string_value(menu->sym));
684 if (sym_set_string_value(menu->sym, input_buf))
686 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
697 static void conf_load(void)
703 cprint("--inputbox");
704 cprint(load_config_text);
707 cprint("%s", filename);
713 if (!conf_read(input_buf))
715 show_textbox(NULL, "File does not exist!", 5, 38);
718 show_helptext("Load Alternate Configuration", load_config_help);
726 static void conf_save(void)
732 cprint("--inputbox");
733 cprint(save_config_text);
736 cprint("%s", filename);
742 if (!conf_write(input_buf))
744 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
747 show_helptext("Save Alternate Configuration", save_config_help);
755 static void conf_cleanup(void)
757 tcsetattr(1, TCSAFLUSH, &ios_org);
759 unlink("lxdialog.scrltmp");
762 int main(int ac, char **av)
771 sym = sym_lookup("KERNELRELEASE", 0);
773 sprintf(menu_backtitle, "Linux Kernel v%s Configuration",
774 sym_get_string_value(sym));
776 mode = getenv("MENUCONFIG_MODE");
778 if (!strcasecmp(mode, "single_menu"))
779 single_menu_mode = 1;
782 tcgetattr(1, &ios_org);
783 atexit(conf_cleanup);
790 cprint("Do you wish to save your new kernel configuration?");
797 if (conf_write(NULL)) {
798 fprintf(stderr, "\n\n"
799 "Error during writing of the kernel configuration.\n"
800 "Your kernel configuration changes were NOT saved."
805 "*** End of Linux kernel configuration.\n"
806 "*** Execute 'make' to build the kernel or try 'make help'."
809 fprintf(stderr, "\n\n"
810 "Your kernel configuration changes were NOT saved."