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 Buildroot\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 "Buildroot'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 Buildroot\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
));
318 val
= sym_get_tristate_value(sym
);
319 if (sym_is_choice_value(sym
) && val
== yes
) {
320 cprint_tag(":%p", menu
);
325 cprint_tag("t%p", menu
);
326 if (sym_is_changable(sym
))
327 cprint_name("[%c]", val
== no
? ' ' : '*');
332 cprint_tag("t%p", menu
);
334 case yes
: ch
= '*'; break;
335 case mod
: ch
= 'M'; break;
336 default: ch
= ' '; break;
338 if (sym_is_changable(sym
))
339 cprint_name("<%c>", ch
);
344 cprint_tag("s%p", menu
);
345 tmp
= cprint_name("(%s)", sym_get_string_value(sym
));
346 tmp
= indent
- tmp
+ 4;
349 cprint_name("%*c%s%s", tmp
, ' ', menu_get_prompt(menu
),
350 (sym_has_value(sym
) || !sym_is_changable(sym
)) ?
355 cprint_name("%*c%s%s", indent
+ 1, ' ', menu_get_prompt(menu
),
356 (sym_has_value(sym
) || !sym_is_changable(sym
)) ?
358 if (menu
->prompt
->type
== P_MENU
) {
359 cprint_name(" --->");
366 for (child
= menu
->list
; child
; child
= child
->next
)
371 static void conf(struct menu
*menu
)
373 struct dialog_list_item
*active_item
= NULL
;
374 struct menu
*submenu
;
375 const char *prompt
= menu_get_prompt(menu
);
377 char active_entry
[40];
380 unlink("lxdialog.scrltmp");
390 if (menu
== &rootmenu
) {
391 cmake(); cprint_tag(":"); cprint_name("--- ");
392 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
393 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
396 stat
= dialog_menu(prompt
? prompt
: "Main Menu",
397 menu_instructions
, rows
, cols
, rows
- 10,
398 active_entry
, item_no
, items
);
402 if (stat
== 1 || stat
== 255)
405 active_item
= first_sel_item(item_no
, items
);
408 active_item
->selected
= 0;
409 strncpy(active_entry
, active_item
->tag
, sizeof(active_entry
));
410 active_entry
[sizeof(active_entry
)-1] = 0;
411 type
= active_entry
[0];
417 if (sscanf(active_entry
+ 1, "%p", &submenu
) == 1)
424 if (single_menu_mode
)
425 submenu
->data
= (void *) (long) !submenu
->data
;
430 if (sym_is_choice(sym
) && sym_get_tristate_value(sym
) == yes
)
431 conf_choice(submenu
);
432 else if (submenu
->prompt
->type
== P_MENU
)
436 conf_string(submenu
);
454 if (sym_set_tristate_value(sym
, yes
))
456 if (sym_set_tristate_value(sym
, mod
))
457 show_textbox(NULL
, setmod_text
, 6, 74);
462 sym_set_tristate_value(sym
, no
);
466 sym_set_tristate_value(sym
, mod
);
470 sym_toggle_tristate_value(sym
);
471 else if (type
== 'm')
478 static void show_textbox(const char *title
, const char *text
, int r
, int c
)
482 fd
= creat(".help.tmp", 0777);
483 write(fd
, text
, strlen(text
));
485 while (dialog_textbox(title
, ".help.tmp", r
, c
) < 0)
490 static void show_helptext(const char *title
, const char *text
)
492 show_textbox(title
, text
, rows
, cols
);
495 static void show_help(struct menu
*menu
)
499 struct symbol
*sym
= menu
->sym
;
505 helptext
= malloc(strlen(sym
->name
) + strlen(help
) + 16);
506 sprintf(helptext
, "%s:\n\n%s", sym
->name
, help
);
507 show_helptext(menu_get_prompt(menu
), helptext
);
510 show_helptext(menu_get_prompt(menu
), help
);
513 static void show_readme(void)
515 show_helptext("Help", top_menu_help
);
518 static void conf_choice(struct menu
*menu
)
520 const char *prompt
= menu_get_prompt(menu
);
522 struct symbol
*active
;
524 active
= sym_get_choice_value(menu
->sym
);
528 for (child
= menu
->list
; child
; child
= child
->next
) {
529 if (!menu_is_visible(child
))
532 cprint_tag("%p", child
);
533 cprint_name("%s", menu_get_prompt(child
));
534 if (child
->sym
== sym_get_choice_value(menu
->sym
))
535 items
[item_no
- 1]->selected
= 1; /* ON */
536 else if (child
->sym
== active
)
537 items
[item_no
- 1]->selected
= 2; /* SELECTED */
539 items
[item_no
- 1]->selected
= 0; /* OFF */
542 switch (dialog_checklist(prompt
? prompt
: "Main Menu",
543 radiolist_instructions
, 15, 70, 6,
544 item_no
, items
, FLAG_RADIO
)) {
546 if (sscanf(first_sel_item(item_no
, items
)->tag
, "%p", &child
) != 1)
548 sym_set_tristate_value(child
->sym
, yes
);
551 if (sscanf(first_sel_item(item_no
, items
)->tag
, "%p", &child
) == 1) {
563 static void conf_string(struct menu
*menu
)
565 const char *prompt
= menu_get_prompt(menu
);
570 switch (sym_get_type(menu
->sym
)) {
572 heading
= (char *) inputbox_instructions_int
;
575 heading
= (char *) inputbox_instructions_hex
;
578 heading
= (char *) inputbox_instructions_string
;
581 heading
= "Internal mconf error!";
585 switch (dialog_inputbox(prompt
? prompt
: "Main Menu",
587 sym_get_string_value(menu
->sym
))) {
589 if (sym_set_string_value(menu
->sym
, dialog_input_result
))
591 show_textbox(NULL
, "You have made an invalid entry.", 5, 43);
602 static void conf_load(void)
605 switch (dialog_inputbox(NULL
, load_config_text
, 11, 55,
608 if (!dialog_input_result
[0])
610 if (!conf_read(dialog_input_result
))
612 show_textbox(NULL
, "File does not exist!", 5, 38);
615 show_helptext("Load Alternate Configuration", load_config_help
);
623 static void conf_save(void)
626 switch (dialog_inputbox(NULL
, save_config_text
, 11, 55,
629 if (!dialog_input_result
[0])
631 if (!conf_write(dialog_input_result
))
633 show_textbox(NULL
, "Can't create file! Probably a nonexistent directory.", 5, 60);
636 show_helptext("Save Alternate Configuration", save_config_help
);
644 static void conf_cleanup(void)
646 tcsetattr(1, TCSAFLUSH
, &ios_org
);
650 static void winch_handler(int sig
)
654 if (ioctl(1, TIOCGWINSZ
, &ws
) == -1) {
662 if (rows
< 19 || cols
< 80) {
664 fprintf(stderr
, "Your display is too small to run Menuconfig!\n");
665 fprintf(stderr
, "It must be at least 19 lines by 80 columns.\n");
674 int main(int ac
, char **av
)
683 sym
= sym_lookup("VERSION", 0);
685 snprintf(menu_backtitle
, 128, "Buildroot v%s Configuration",
686 sym_get_string_value(sym
));
688 mode
= getenv("MENUCONFIG_MODE");
690 if (!strcasecmp(mode
, "single_menu"))
691 single_menu_mode
= 1;
694 tcgetattr(1, &ios_org
);
695 atexit(conf_cleanup
);
698 signal(SIGWINCH
, winch_handler
);
702 /* Restart dialog to act more like when lxdialog was still separate */
705 stat
= dialog_yesno(NULL
,
706 "Do you wish to save your new Buildroot configuration?", 5, 60);
713 "*** End of Buildroot configuration.\n"
714 "*** Check the top-level Makefile for additional configuration options.\n\n");
716 printf("\n\nYour Buildroot configuration changes were NOT saved.\n\n");