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 * Directly use liblxdialog library routines.
9 * 2002-11-14 Petr Baudis <pasky@ucw.cz>
12 #include <sys/ioctl.h>
14 #include <sys/termios.h>
28 #define LKC_DIRECT_LINK
31 static char menu_backtitle[128];
32 static const char menu_instructions[] =
33 "Arrow keys navigate the menu. "
34 "<Enter> selects submenus --->. "
35 "Highlighted letters are hotkeys. "
36 "Pressing <Y> selectes a feature, while <N> will exclude a feature. "
37 "Press <Esc><Esc> to exit, <?> for Help. "
38 "Legend: [*] feature is selected [ ] feature is excluded",
39 radiolist_instructions[] =
40 "Use the arrow keys to navigate this window or "
41 "press the hotkey of the item you wish to select "
42 "followed by the <SPACE BAR>. "
43 "Press <?> for additional information about this option.",
44 inputbox_instructions_int[] =
45 "Please enter a decimal value. "
46 "Fractions will not be accepted. "
47 "Use the <TAB> key to move from the input field to the buttons below it.",
48 inputbox_instructions_hex[] =
49 "Please enter a hexadecimal value. "
50 "Use the <TAB> key to move from the input field to the buttons below it.",
51 inputbox_instructions_string[] =
52 "Please enter a string value. "
53 "Use the <TAB> key to move from the input field to the buttons below it.",
55 "This feature depends on another which has been configured as a module.\n"
56 "As a result, this feature will be built as a module.",
58 "There is no help available for this option.\n",
60 "Enter the name of the configuration file you wish to load. "
61 "Accept the name shown to restore the configuration you "
62 "last retrieved. Leave blank to abort.",
65 "For various reasons, one may wish to keep several different uClibc\n"
66 "configurations available on a single machine.\n"
68 "If you have saved a previous configuration in a file other than the\n"
69 "uClibc's default, entering the name of the file here will allow you\n"
70 "to modify that configuration.\n"
72 "If you are uncertain, then you have probably never used alternate\n"
73 "configuration files. You should therefor leave this blank to abort.\n",
75 "Enter a filename to which this configuration should be saved "
76 "as an alternate. Leave blank to abort.",
79 "For various reasons, one may wish to keep different uClibc\n"
80 "configurations available on a single machine.\n"
82 "Entering a file name here will allow you to later retrieve, modify\n"
83 "and use the current configuration as an alternate to whatever\n"
84 "configuration options you have selected at that time.\n"
86 "If you are uncertain what all this means then you should probably\n"
87 "leave this blank.\n",
90 "Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
91 "you wish to change or submenu wish to select and press <Enter>.\n"
92 "Submenus are designated by \"--->\".\n"
94 "Shortcut: Press the option's highlighted letter (hotkey).\n"
96 "You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
97 "unseen options into view.\n"
100 static char filename[PATH_MAX+1] = ".config";
101 static int indent = 0;
102 static struct termios ios_org;
103 static int rows, cols;
104 struct menu *current_menu;
105 static int child_count;
106 static int single_menu_mode;
108 static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
111 static void conf(struct menu *menu);
112 static void conf_choice(struct menu *menu);
113 static void conf_string(struct menu *menu);
114 static void conf_load(void);
115 static void conf_save(void);
116 static void show_textbox(const char *title, const char *text, int r, int c);
117 static void show_helptext(const char *title, const char *text);
118 static void show_help(struct menu *menu);
119 static void show_readme(void);
121 static void init_wsize(void)
126 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
133 env = getenv("LINES");
140 env = getenv("COLUMNS");
148 if (rows < 19 || cols < 80) {
149 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
150 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
158 static void cinit(void)
163 static void cmake(void)
165 items[item_no] = malloc(sizeof(struct dialog_list_item));
166 memset(items[item_no], 0, sizeof(struct dialog_list_item));
167 items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0;
168 items[item_no]->name = malloc(512); items[item_no]->name[0] = 0;
169 items[item_no]->namelen = 0;
173 static int cprint_name(const char *fmt, ...)
181 res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
182 512 - items[item_no - 1]->namelen, fmt, ap);
184 items[item_no - 1]->namelen += res;
190 static int cprint_tag(const char *fmt, ...)
198 res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
204 static void cdone(void)
208 for (i = 0; i < item_no; i++) {
210 free(items[i]->name);
217 static void build_conf(struct menu *menu)
220 struct property *prop;
222 int type, tmp, doint = 2;
226 if (!menu_is_visible(menu))
232 if (prop && menu != current_menu) {
233 const char *prompt = menu_get_prompt(menu);
234 switch (prop->type) {
238 cprint_tag("m%p", menu);
240 if (single_menu_mode) {
241 cprint_name("%s%*c%s",
242 menu->data ? "-->" : "++>",
243 indent + 1, ' ', prompt);
245 cprint_name(" %*c%s --->", indent + 1, ' ', prompt);
248 if (single_menu_mode && menu->data)
255 cprint_tag(":%p", menu);
256 cprint_name("---%*c%s", indent + 1, ' ', prompt);
265 type = sym_get_type(sym);
266 if (sym_is_choice(sym)) {
267 struct symbol *def_sym = sym_get_choice_value(sym);
268 struct menu *def_menu = NULL;
271 for (child = menu->list; child; child = child->next) {
272 if (menu_is_visible(child) && child->sym == def_sym)
276 val = sym_get_tristate_value(sym);
277 if (sym_is_changable(sym)) {
278 cprint_tag("t%p", menu);
281 cprint_name("[%c]", val == no ? ' ' : '*');
285 case yes: ch = '*'; break;
286 case mod: ch = 'M'; break;
287 default: ch = ' '; break;
289 cprint_name("<%c>", ch);
293 cprint_tag("%c%p", def_menu ? 't' : ':', menu);
297 cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
300 cprint_name(" (%s)", menu_get_prompt(def_menu));
301 cprint_name(" --->");
302 if (def_menu->list) {
304 build_conf(def_menu);
311 if (menu == current_menu) {
312 cprint_tag(":%p", menu);
313 cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
317 val = sym_get_tristate_value(sym);
318 if (sym_is_choice_value(sym) && val == yes) {
319 cprint_tag(":%p", menu);
324 cprint_tag("t%p", menu);
325 if (sym_is_changable(sym))
326 cprint_name("[%c]", val == no ? ' ' : '*');
331 cprint_tag("t%p", menu);
333 case yes: ch = '*'; break;
334 case mod: ch = 'M'; break;
335 default: ch = ' '; break;
337 if (sym_is_changable(sym))
338 cprint_name("<%c>", ch);
343 cprint_tag("s%p", menu);
344 tmp = cprint_name("(%s)", sym_get_string_value(sym));
345 tmp = indent - tmp + 4;
348 cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
349 (sym_has_value(sym) || !sym_is_changable(sym)) ?
354 cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
355 (sym_has_value(sym) || !sym_is_changable(sym)) ?
357 if (menu->prompt->type == P_MENU) {
358 cprint_name(" --->");
365 for (child = menu->list; child; child = child->next)
370 static void conf(struct menu *menu)
372 struct dialog_list_item *active_item = NULL;
373 struct menu *submenu;
374 const char *prompt = menu_get_prompt(menu);
376 char active_entry[40];
379 unlink("lxdialog.scrltmp");
389 if (menu == &rootmenu) {
390 cmake(); cprint_tag(":"); cprint_name("--- ");
391 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
392 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
395 stat = dialog_menu(prompt ? prompt : "Main Menu",
396 menu_instructions, rows, cols, rows - 10,
397 active_entry, item_no, items);
401 if (stat == 1 || stat == 255)
404 active_item = first_sel_item(item_no, items);
407 active_item->selected = 0;
408 strncpy(active_entry, active_item->tag, sizeof(active_entry));
409 active_entry[sizeof(active_entry)-1] = 0;
410 type = active_entry[0];
416 if (sscanf(active_entry + 1, "%p", &submenu) == 1)
423 if (single_menu_mode)
424 submenu->data = (void *) (long) !submenu->data;
429 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
430 conf_choice(submenu);
431 else if (submenu->prompt->type == P_MENU)
435 conf_string(submenu);
453 if (sym_set_tristate_value(sym, yes))
455 if (sym_set_tristate_value(sym, mod))
456 show_textbox(NULL, setmod_text, 6, 74);
461 sym_set_tristate_value(sym, no);
465 sym_set_tristate_value(sym, mod);
469 sym_toggle_tristate_value(sym);
470 else if (type == 'm')
477 static void show_textbox(const char *title, const char *text, int r, int c)
481 fd = creat(".help.tmp", 0777);
482 write(fd, text, strlen(text));
484 while (dialog_textbox(title, ".help.tmp", r, c) < 0)
489 static void show_helptext(const char *title, const char *text)
491 show_textbox(title, text, rows, cols);
494 static void show_help(struct menu *menu)
498 struct symbol *sym = menu->sym;
504 helptext = malloc(strlen(sym->name) + strlen(help) + 16);
505 sprintf(helptext, "%s:\n\n%s", sym->name, help);
506 show_helptext(menu_get_prompt(menu), helptext);
509 show_helptext(menu_get_prompt(menu), help);
512 static void show_readme(void)
514 show_helptext("Help", top_menu_help);
517 static void conf_choice(struct menu *menu)
519 const char *prompt = menu_get_prompt(menu);
521 struct symbol *active;
523 active = sym_get_choice_value(menu->sym);
527 for (child = menu->list; child; child = child->next) {
528 if (!menu_is_visible(child))
531 cprint_tag("%p", child);
532 cprint_name("%s", menu_get_prompt(child));
533 if (child->sym == sym_get_choice_value(menu->sym))
534 items[item_no - 1]->selected = 1; /* ON */
535 else if (child->sym == active)
536 items[item_no - 1]->selected = 2; /* SELECTED */
538 items[item_no - 1]->selected = 0; /* OFF */
541 switch (dialog_checklist(prompt ? prompt : "Main Menu",
542 radiolist_instructions, 15, 70, 6,
543 item_no, items, FLAG_RADIO)) {
545 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
547 sym_set_tristate_value(child->sym, yes);
550 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
562 static void conf_string(struct menu *menu)
564 const char *prompt = menu_get_prompt(menu);
569 switch (sym_get_type(menu->sym)) {
571 heading = (char *) inputbox_instructions_int;
574 heading = (char *) inputbox_instructions_hex;
577 heading = (char *) inputbox_instructions_string;
580 heading = "Internal mconf error!";
584 switch (dialog_inputbox(prompt ? prompt : "Main Menu",
586 sym_get_string_value(menu->sym))) {
588 if (sym_set_string_value(menu->sym, dialog_input_result))
590 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
601 static void conf_load(void)
604 switch (dialog_inputbox(NULL, load_config_text, 11, 55,
607 if (!dialog_input_result[0])
609 if (!conf_read(dialog_input_result))
611 show_textbox(NULL, "File does not exist!", 5, 38);
614 show_helptext("Load Alternate Configuration", load_config_help);
622 static void conf_save(void)
625 switch (dialog_inputbox(NULL, save_config_text, 11, 55,
628 if (!dialog_input_result[0])
630 if (!conf_write(dialog_input_result))
632 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
635 show_helptext("Save Alternate Configuration", save_config_help);
643 static void conf_cleanup(void)
645 tcsetattr(1, TCSAFLUSH, &ios_org);
649 static void winch_handler(int sig)
653 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
661 if (rows < 19 || cols < 80) {
663 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
664 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
673 int main(int ac, char **av)
682 sym = sym_lookup("VERSION", 0);
684 snprintf(menu_backtitle, 128, "uClibc v%s Configuration",
685 sym_get_string_value(sym));
687 mode = getenv("MENUCONFIG_MODE");
689 if (!strcasecmp(mode, "single_menu"))
690 single_menu_mode = 1;
693 tcgetattr(1, &ios_org);
694 atexit(conf_cleanup);
697 signal(SIGWINCH, winch_handler);
701 /* Restart dialog to act more like when lxdialog was still separate */
704 stat = dialog_yesno(NULL,
705 "Do you wish to save your new uClibc configuration?", 5, 60);
712 "*** End of uClibc configuration.\n"
713 "*** Check the top-level Makefile for additional configuration options.\n\n");
715 printf("\n\nYour uClibc configuration changes were NOT saved.\n\n");