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 static 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
);
312 val
= sym_get_tristate_value(sym
);
313 if (sym_is_choice_value(sym
) && val
== yes
) {
314 cprint_tag(":%p", menu
);
319 cprint_tag("t%p", menu
);
320 if (sym_is_changable(sym
))
321 cprint_name("[%c]", val
== no
? ' ' : '*');
326 cprint_tag("t%p", menu
);
328 case yes
: ch
= '*'; break;
329 case mod
: ch
= 'M'; break;
330 default: ch
= ' '; break;
332 if (sym_is_changable(sym
))
333 cprint_name("<%c>", ch
);
338 cprint_tag("s%p", menu
);
339 tmp
= cprint_name("(%s)", sym_get_string_value(sym
));
340 tmp
= indent
- tmp
+ 4;
343 cprint_name("%*c%s%s", tmp
, ' ', menu_get_prompt(menu
),
344 (sym_has_value(sym
) || !sym_is_changable(sym
)) ?
349 cprint_name("%*c%s%s", indent
+ 1, ' ', menu_get_prompt(menu
),
350 (sym_has_value(sym
) || !sym_is_changable(sym
)) ?
352 if (menu
->prompt
->type
== P_MENU
) {
353 cprint_name(" --->");
360 for (child
= menu
->list
; child
; child
= child
->next
)
365 static void conf(struct menu
*menu
)
367 struct dialog_list_item
*active_item
= NULL
;
368 struct menu
*submenu
;
369 const char *prompt
= menu_get_prompt(menu
);
371 char active_entry
[40];
374 unlink("lxdialog.scrltmp");
384 if (menu
== &rootmenu
) {
385 cmake(); cprint_tag(":"); cprint_name("--- ");
386 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
387 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
390 stat
= dialog_menu(prompt
? prompt
: "Main Menu",
391 menu_instructions
, rows
, cols
, rows
- 10,
392 active_entry
, item_no
, items
);
396 if (stat
== 1 || stat
== 255)
399 active_item
= first_sel_item(item_no
, items
);
402 active_item
->selected
= 0;
403 strncpy(active_entry
, active_item
->tag
, sizeof(active_entry
));
404 active_entry
[sizeof(active_entry
)-1] = 0;
405 type
= active_entry
[0];
411 if (sscanf(active_entry
+ 1, "%p", &submenu
) == 1)
418 if (single_menu_mode
)
419 submenu
->data
= (void *) (long) !submenu
->data
;
424 if (sym_is_choice(sym
) && sym_get_tristate_value(sym
) == yes
)
425 conf_choice(submenu
);
426 else if (submenu
->prompt
->type
== P_MENU
)
430 conf_string(submenu
);
448 if (sym_set_tristate_value(sym
, yes
))
450 if (sym_set_tristate_value(sym
, mod
))
451 show_textbox(NULL
, setmod_text
, 6, 74);
456 sym_set_tristate_value(sym
, no
);
460 sym_set_tristate_value(sym
, mod
);
464 sym_toggle_tristate_value(sym
);
465 else if (type
== 'm')
472 static void show_textbox(const char *title
, const char *text
, int r
, int c
)
476 fd
= creat(".help.tmp", 0777);
477 write(fd
, text
, strlen(text
));
479 while (dialog_textbox(title
, ".help.tmp", r
, c
) < 0)
484 static void show_helptext(const char *title
, const char *text
)
486 show_textbox(title
, text
, rows
, cols
);
489 static void show_help(struct menu
*menu
)
493 struct symbol
*sym
= menu
->sym
;
499 helptext
= malloc(strlen(sym
->name
) + strlen(help
) + 16);
500 sprintf(helptext
, "%s:\n\n%s", sym
->name
, help
);
501 show_helptext(menu_get_prompt(menu
), helptext
);
504 show_helptext(menu_get_prompt(menu
), help
);
507 static void show_readme(void)
509 show_helptext("Help", top_menu_help
);
512 static void conf_choice(struct menu
*menu
)
514 const char *prompt
= menu_get_prompt(menu
);
516 struct symbol
*active
;
518 active
= sym_get_choice_value(menu
->sym
);
522 for (child
= menu
->list
; child
; child
= child
->next
) {
523 if (!menu_is_visible(child
))
526 cprint_tag("%p", child
);
527 cprint_name("%s", menu_get_prompt(child
));
528 if (child
->sym
== sym_get_choice_value(menu
->sym
))
529 items
[item_no
- 1]->selected
= 1; /* ON */
530 else if (child
->sym
== active
)
531 items
[item_no
- 1]->selected
= 2; /* SELECTED */
533 items
[item_no
- 1]->selected
= 0; /* OFF */
536 switch (dialog_checklist(prompt
? prompt
: "Main Menu",
537 radiolist_instructions
, 15, 70, 6,
538 item_no
, items
, FLAG_RADIO
)) {
540 if (sscanf(first_sel_item(item_no
, items
)->tag
, "%p", &child
) != 1)
542 sym_set_tristate_value(child
->sym
, yes
);
545 if (sscanf(first_sel_item(item_no
, items
)->tag
, "%p", &child
) == 1) {
557 static void conf_string(struct menu
*menu
)
559 const char *prompt
= menu_get_prompt(menu
);
564 switch (sym_get_type(menu
->sym
)) {
566 heading
= (char *) inputbox_instructions_int
;
569 heading
= (char *) inputbox_instructions_hex
;
572 heading
= (char *) inputbox_instructions_string
;
575 heading
= "Internal mconf error!";
579 switch (dialog_inputbox(prompt
? prompt
: "Main Menu",
581 sym_get_string_value(menu
->sym
))) {
583 if (sym_set_string_value(menu
->sym
, dialog_input_result
))
585 show_textbox(NULL
, "You have made an invalid entry.", 5, 43);
596 static void conf_load(void)
599 switch (dialog_inputbox(NULL
, load_config_text
, 11, 55,
602 if (!dialog_input_result
[0])
604 if (!conf_read(dialog_input_result
))
606 show_textbox(NULL
, "File does not exist!", 5, 38);
609 show_helptext("Load Alternate Configuration", load_config_help
);
617 static void conf_save(void)
620 switch (dialog_inputbox(NULL
, save_config_text
, 11, 55,
623 if (!dialog_input_result
[0])
625 if (!conf_write(dialog_input_result
))
627 show_textbox(NULL
, "Can't create file! Probably a nonexistent directory.", 5, 60);
630 show_helptext("Save Alternate Configuration", save_config_help
);
638 static void conf_cleanup(void)
640 tcsetattr(1, TCSAFLUSH
, &ios_org
);
644 static void winch_handler(int sig
)
648 if (ioctl(1, TIOCGWINSZ
, &ws
) == -1) {
656 if (rows
< 19 || cols
< 80) {
658 fprintf(stderr
, "Your display is too small to run Menuconfig!\n");
659 fprintf(stderr
, "It must be at least 19 lines by 80 columns.\n");
668 int main(int ac
, char **av
)
677 sym
= sym_lookup("VERSION", 0);
679 snprintf(menu_backtitle
, 128, "Buildroot v%s Configuration",
680 sym_get_string_value(sym
));
682 mode
= getenv("MENUCONFIG_MODE");
684 if (!strcasecmp(mode
, "single_menu"))
685 single_menu_mode
= 1;
688 tcgetattr(1, &ios_org
);
689 atexit(conf_cleanup
);
692 signal(SIGWINCH
, winch_handler
);
696 /* Restart dialog to act more like when lxdialog was still separate */
699 stat
= dialog_yesno(NULL
,
700 "Do you wish to save your new Buildroot configuration?", 5, 60);
707 "*** End of Buildroot configuration.\n"
708 "*** After changing root fs, use make linux-dirclean.\n"
709 "*** Check the top-level Makefile for additional configuration options.\n\n");
711 printf("\n\nYour Buildroot configuration changes were NOT saved.\n\n");