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 = 0, cols = 0;
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(STDIN_FILENO, TIOCGWINSZ, &ws)) {
122 env = getenv("LINES");
129 env = getenv("COLUMNS");
136 if (rows < 19 || cols < 80) {
137 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
138 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
146 static void cprint_init(void)
150 memset(args, 0, sizeof(args));
153 cprint("./scripts/lxdialog/lxdialog");
154 cprint("--backtitle");
155 cprint(menu_backtitle);
158 static int cprint1(const char *fmt, ...)
166 res = vsprintf(bufptr, fmt, ap);
173 static void cprint_done(void)
179 static int cprint(const char *fmt, ...)
186 res = vsprintf(bufptr, fmt, ap);
196 static void winch_handler(int sig)
204 static int exec_conf(void)
206 int pipefd[2], stat, size;
208 sigset_t sset, osset;
211 sigaddset(&sset, SIGINT);
212 sigprocmask(SIG_BLOCK, &sset, &osset);
214 signal(SIGINT, SIG_DFL);
216 sa.sa_handler = winch_handler;
217 sigemptyset(&sa.sa_mask);
218 sa.sa_flags = SA_RESTART;
219 sigaction(SIGWINCH, &sa, NULL);
226 sigprocmask(SIG_SETMASK, &osset, NULL);
230 execv(args[0], args);
237 size = input_buf + sizeof(input_buf) - bufptr;
238 size = read(pipefd[0], bufptr, size);
241 if (errno == EINTR || errno == EAGAIN)
251 waitpid(pid, &stat, 0);
256 sigprocmask(SIG_SETMASK, &osset, NULL);
259 if (WIFSIGNALED(stat)) {
260 printf("\finterrupted(%d)\n", WTERMSIG(stat));
264 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
268 if (sigismember(&sset, SIGINT)) {
269 printf("\finterrupted\n");
272 sigprocmask(SIG_SETMASK, &osset, NULL);
274 return WEXITSTATUS(stat);
277 static void build_conf(struct menu *menu)
280 struct property *prop;
282 int type, tmp, doint = 2;
286 if (!menu_is_visible(menu))
292 if (prop && menu != current_menu) {
293 const char *prompt = menu_get_prompt(menu);
294 switch (prop->type) {
299 if (single_menu_mode) {
301 menu->data ? "-->" : "++>",
302 indent + 1, ' ', prompt);
304 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
307 if (single_menu_mode && menu->data)
314 cprint("---%*c%s", indent + 1, ' ', prompt);
322 type = sym_get_type(sym);
323 if (sym_is_choice(sym)) {
324 struct symbol *def_sym = sym_get_choice_value(sym);
325 struct menu *def_menu = NULL;
328 for (child = menu->list; child; child = child->next) {
329 if (menu_is_visible(child) && child->sym == def_sym)
333 val = sym_get_tristate_value(sym);
334 if (sym_is_changable(sym)) {
338 cprint1("[%c]", val == no ? ' ' : '*');
342 case yes: ch = '*'; break;
343 case mod: ch = 'M'; break;
344 default: ch = ' '; break;
350 cprint("%c%p", def_menu ? 't' : ':', menu);
354 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
357 cprint1(" (%s)", menu_get_prompt(def_menu));
360 if (def_menu->list) {
362 build_conf(def_menu);
371 if (menu == current_menu) {
373 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
377 val = sym_get_tristate_value(sym);
378 if (sym_is_choice_value(sym) && val == yes) {
385 if (sym_is_changable(sym))
386 cprint1("[%c]", val == no ? ' ' : '*');
393 case yes: ch = '*'; break;
394 case mod: ch = 'M'; break;
395 default: ch = ' '; break;
397 if (sym_is_changable(sym))
404 tmp = cprint1("(%s)", sym_get_string_value(sym));
405 tmp = indent - tmp + 4;
408 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
409 (sym_has_value(sym) || !sym_is_changable(sym)) ?
415 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
416 (sym_has_value(sym) || !sym_is_changable(sym)) ?
418 if (menu->prompt->type == P_MENU) {
428 for (child = menu->list; child; child = child->next)
433 static void conf(struct menu *menu)
435 struct menu *submenu;
436 const char *prompt = menu_get_prompt(menu);
438 char active_entry[40];
441 unlink("lxdialog.scrltmp");
446 cprint("%s", prompt ? prompt : "Main Menu");
448 cprint(menu_instructions);
451 cprint("%d", rows - 10);
452 cprint("%s", active_entry);
457 if (menu == &rootmenu) {
461 cprint(" Load an Alternate Configuration File");
463 cprint(" Save Configuration to an Alternate File");
469 if (stat == 1 || stat == 255)
476 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
478 if (i >= sizeof(active_entry))
479 i = sizeof(active_entry) - 1;
481 strcpy(active_entry, input_buf);
485 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
492 if (single_menu_mode)
493 submenu->data = (void *) (long) !submenu->data;
498 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
499 conf_choice(submenu);
500 else if (submenu->prompt->type == P_MENU)
504 conf_string(submenu);
522 if (sym_set_tristate_value(sym, yes))
524 if (sym_set_tristate_value(sym, mod))
525 show_textbox(NULL, setmod_text, 6, 74);
530 sym_set_tristate_value(sym, no);
534 sym_set_tristate_value(sym, mod);
538 sym_toggle_tristate_value(sym);
539 else if (type == 'm')
546 static void show_textbox(const char *title, const char *text, int r, int c)
550 fd = creat(".help.tmp", 0777);
551 write(fd, text, strlen(text));
563 } while (exec_conf() < 0);
567 static void show_helptext(const char *title, const char *text)
569 show_textbox(title, text, rows, cols);
572 static void show_help(struct menu *menu)
576 struct symbol *sym = menu->sym;
582 helptext = malloc(strlen(sym->name) + strlen(help) + 16);
583 sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help);
584 show_helptext(menu_get_prompt(menu), helptext);
587 show_helptext(menu_get_prompt(menu), help);
590 static void show_readme(void)
595 cprint("scripts/README.Menuconfig");
598 } while (exec_conf() == -1);
601 static void conf_choice(struct menu *menu)
603 const char *prompt = menu_get_prompt(menu);
605 struct symbol *active;
608 active = sym_get_choice_value(menu->sym);
612 cprint("%s", prompt ? prompt : "Main Menu");
613 cprint("--radiolist");
614 cprint(radiolist_instructions);
620 for (child = menu->list; child; child = child->next) {
621 if (!menu_is_visible(child))
624 cprint("%s", menu_get_prompt(child));
625 if (child->sym == sym_get_choice_value(menu->sym))
627 else if (child->sym == active)
636 if (sscanf(input_buf, "%p", &child) != 1)
638 sym_set_tristate_value(child->sym, yes);
641 if (sscanf(input_buf, "%p", &child) == 1) {
653 static void conf_string(struct menu *menu)
655 const char *prompt = menu_get_prompt(menu);
661 cprint("%s", prompt ? prompt : "Main Menu");
662 cprint("--inputbox");
663 switch (sym_get_type(menu->sym)) {
665 cprint(inputbox_instructions_int);
668 cprint(inputbox_instructions_hex);
671 cprint(inputbox_instructions_string);
678 cprint("%s", sym_get_string_value(menu->sym));
682 if (sym_set_string_value(menu->sym, input_buf))
684 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
695 static void conf_load(void)
701 cprint("--inputbox");
702 cprint(load_config_text);
705 cprint("%s", filename);
711 if (!conf_read(input_buf))
713 show_textbox(NULL, "File does not exist!", 5, 38);
716 show_helptext("Load Alternate Configuration", load_config_help);
724 static void conf_save(void)
730 cprint("--inputbox");
731 cprint(save_config_text);
734 cprint("%s", filename);
740 if (!conf_write(input_buf))
742 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
745 show_helptext("Save Alternate Configuration", save_config_help);
753 static void conf_cleanup(void)
755 tcsetattr(1, TCSAFLUSH, &ios_org);
757 unlink("lxdialog.scrltmp");
760 int main(int ac, char **av)
769 sym = sym_lookup("KERNELRELEASE", 0);
771 sprintf(menu_backtitle, "Linux Kernel v%s Configuration",
772 sym_get_string_value(sym));
774 mode = getenv("MENUCONFIG_MODE");
776 if (!strcasecmp(mode, "single_menu"))
777 single_menu_mode = 1;
780 tcgetattr(1, &ios_org);
781 atexit(conf_cleanup);
788 cprint("Do you wish to save your new kernel configuration?");
795 if (conf_write(NULL)) {
796 fprintf(stderr, "\n\n"
797 "Error during writing of the kernel configuration.\n"
798 "Your kernel configuration changes were NOT saved."
803 "*** End of Linux kernel configuration.\n"
804 "*** Execute 'make' to build the kernel or try 'make help'."
807 fprintf(stderr, "\n\n"
808 "Your kernel configuration changes were NOT saved."