blob: 5bc2abdd87313e542684e405bce869df75d287d5 [file] [log] [blame]
Eric Andersenc9f20d92002-12-05 08:41:41 +00001/*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 *
5 * Introduced single menu mode (show all sub-menus in one large tree).
6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7 *
8 * Directly use liblxdialog library routines.
9 * 2002-11-14 Petr Baudis <pasky@ucw.cz>
10 */
11
12#include <sys/ioctl.h>
13#include <sys/wait.h>
14#include <sys/termios.h>
15#include <ctype.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <limits.h>
19#include <signal.h>
20#include <stdarg.h>
21#include <stdlib.h>
22#include <string.h>
23#include <termios.h>
24#include <unistd.h>
25
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +000026#include "lxdialog/dialog.h"
Eric Andersenc9f20d92002-12-05 08:41:41 +000027
28#define LKC_DIRECT_LINK
29#include "lkc.h"
30
Eric Andersen72d8e442003-08-05 02:18:25 +000031static char menu_backtitle[128];
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +000032static const char mconf_readme[] =
33"Overview\n"
34"--------\n"
35"Some features may be built directly into BusyBox. Some features\n"
36"may be completely removed altogether. There are also certain\n"
37"parameters which are not really features, but must be\n"
38"entered in as decimal or hexadecimal numbers or possibly text.\n"
39"\n"
40"Menu items beginning with [*] or [ ] represent features\n"
41"configured to be built in or removed respectively.\n"
42"\n"
43"To change any of these features, highlight it with the cursor\n"
44"keys and press <Y> to build it in or <N> to removed it.\n"
45"You may also press the <Space Bar> to cycle\n"
46"through the available options (ie. Y->N->Y).\n"
47"\n"
48"Some additional keyboard hints:\n"
49"\n"
50"Menus\n"
51"----------\n"
52"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
53" you wish to change or submenu wish to select and press <Enter>.\n"
54" Submenus are designated by \"--->\".\n"
55"\n"
56" Shortcut: Press the option's highlighted letter (hotkey).\n"
57" Pressing a hotkey more than once will sequence\n"
58" through all visible items which use that hotkey.\n"
59"\n"
60" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
61" unseen options into view.\n"
62"\n"
63"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
64" and press <ENTER>.\n"
65"\n"
66" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
67" using those letters. You may press a single <ESC>, but\n"
68" there is a delayed response which you may find annoying.\n"
69"\n"
70" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
71" <Exit> and <Help>\n"
72"\n"
73"o To get help with an item, use the cursor keys to highlight <Help>\n"
74" and Press <ENTER>.\n"
75"\n"
76" Shortcut: Press <H> or <?>.\n"
77"\n"
78"\n"
79"Radiolists (Choice lists)\n"
80"-----------\n"
81"o Use the cursor keys to select the option you wish to set and press\n"
82" <S> or the <SPACE BAR>.\n"
83"\n"
84" Shortcut: Press the first letter of the option you wish to set then\n"
85" press <S> or <SPACE BAR>.\n"
86"\n"
87"o To see available help for the item, use the cursor keys to highlight\n"
88" <Help> and Press <ENTER>.\n"
89"\n"
90" Shortcut: Press <H> or <?>.\n"
91"\n"
92" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
93" <Help>\n"
94"\n"
95"\n"
96"Data Entry\n"
97"-----------\n"
98"o Enter the requested information and press <ENTER>\n"
99" If you are entering hexadecimal values, it is not necessary to\n"
100" add the '0x' prefix to the entry.\n"
101"\n"
102"o For help, use the <TAB> or cursor keys to highlight the help option\n"
103" and press <ENTER>. You can try <TAB><H> as well.\n"
104"\n"
105"\n"
106"Text Box (Help Window)\n"
107"--------\n"
108"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
109" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
110" who are familiar with less and lynx.\n"
111"\n"
112"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
113"\n"
114"\n"
115"Alternate Configuration Files\n"
116"-----------------------------\n"
117"Menuconfig supports the use of alternate configuration files for\n"
118"those who, for various reasons, find it necessary to switch\n"
119"between different configurations.\n"
120"\n"
121"At the end of the main menu you will find two options. One is\n"
122"for saving the current configuration to a file of your choosing.\n"
123"The other option is for loading a previously saved alternate\n"
124"configuration.\n"
125"\n"
126"Even if you don't use alternate configuration files, but you\n"
127"find during a Menuconfig session that you have completely messed\n"
128"up your settings, you may use the \"Load Alternate...\" option to\n"
129"restore your previously saved settings from \".config\" without\n"
130"restarting Menuconfig.\n"
131"\n"
132"Other information\n"
133"-----------------\n"
134"If you use Menuconfig in an XTERM window make sure you have your\n"
135"$TERM variable set to point to a xterm definition which supports color.\n"
136"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
137"display correctly in a RXVT window because rxvt displays only one\n"
138"intensity of color, bright.\n"
139"\n"
140"Menuconfig will display larger menus on screens or xterms which are\n"
141"set to display more than the standard 25 row by 80 column geometry.\n"
142"In order for this to work, the \"stty size\" command must be able to\n"
143"display the screen's current row and column geometry. I STRONGLY\n"
144"RECOMMEND that you make sure you do NOT have the shell variables\n"
145"LINES and COLUMNS exported into your environment. Some distributions\n"
146"export those variables via /etc/profile. Some ncurses programs can\n"
147"become confused when those variables (LINES & COLUMNS) don't reflect\n"
148"the true screen size.\n"
149"\n"
150"Optional personality available\n"
151"------------------------------\n"
152"If you prefer to have all of the options listed in a single\n"
153"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
154"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
155"\n"
156"make MENUCONFIG_MODE=single_menu menuconfig\n"
157"\n"
158"<Enter> will then unroll the appropriate category, or enfold it if it\n"
159"is already unrolled.\n"
160"\n"
161"Note that this mode can eventually be a little more CPU expensive\n"
162"(especially with a larger number of unrolled categories) than the\n"
163"default mode.\n",
164menu_instructions[] =
Eric Andersenc9f20d92002-12-05 08:41:41 +0000165 "Arrow keys navigate the menu. "
166 "<Enter> selects submenus --->. "
167 "Highlighted letters are hotkeys. "
168 "Pressing <Y> selectes a feature, while <N> will exclude a feature. "
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000169 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
Eric Andersenc9f20d92002-12-05 08:41:41 +0000170 "Legend: [*] feature is selected [ ] feature is excluded",
171radiolist_instructions[] =
172 "Use the arrow keys to navigate this window or "
173 "press the hotkey of the item you wish to select "
174 "followed by the <SPACE BAR>. "
175 "Press <?> for additional information about this option.",
176inputbox_instructions_int[] =
177 "Please enter a decimal value. "
178 "Fractions will not be accepted. "
179 "Use the <TAB> key to move from the input field to the buttons below it.",
180inputbox_instructions_hex[] =
181 "Please enter a hexadecimal value. "
182 "Use the <TAB> key to move from the input field to the buttons below it.",
183inputbox_instructions_string[] =
184 "Please enter a string value. "
185 "Use the <TAB> key to move from the input field to the buttons below it.",
186setmod_text[] =
187 "This feature depends on another which has been configured as a module.\n"
188 "As a result, this feature will be built as a module.",
189nohelp_text[] =
190 "There is no help available for this option.\n",
191load_config_text[] =
192 "Enter the name of the configuration file you wish to load. "
193 "Accept the name shown to restore the configuration you "
194 "last retrieved. Leave blank to abort.",
195load_config_help[] =
196 "\n"
197 "For various reasons, one may wish to keep several different BusyBox\n"
198 "configurations available on a single machine.\n"
199 "\n"
200 "If you have saved a previous configuration in a file other than the\n"
Eric Andersen72d8e442003-08-05 02:18:25 +0000201 "BusyBox's default, entering the name of the file here will allow you\n"
Eric Andersenc9f20d92002-12-05 08:41:41 +0000202 "to modify that configuration.\n"
203 "\n"
204 "If you are uncertain, then you have probably never used alternate\n"
205 "configuration files. You should therefor leave this blank to abort.\n",
206save_config_text[] =
207 "Enter a filename to which this configuration should be saved "
208 "as an alternate. Leave blank to abort.",
209save_config_help[] =
210 "\n"
211 "For various reasons, one may wish to keep different BusyBox\n"
212 "configurations available on a single machine.\n"
213 "\n"
214 "Entering a file name here will allow you to later retrieve, modify\n"
215 "and use the current configuration as an alternate to whatever\n"
216 "configuration options you have selected at that time.\n"
217 "\n"
218 "If you are uncertain what all this means then you should probably\n"
Eric Andersena63d09a2003-06-30 18:14:36 +0000219 "leave this blank.\n",
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000220search_help[] =
Eric Andersena63d09a2003-06-30 18:14:36 +0000221 "\n"
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000222 "Search for CONFIG_ symbols and display their relations.\n"
223 "Example: search for \"^FOO\"\n"
224 "Result:\n"
225 "-----------------------------------------------------------------\n"
226 "Symbol: FOO [=m]\n"
227 "Prompt: Foo bus is used to drive the bar HW\n"
228 "Defined at drivers/pci/Kconfig:47\n"
229 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
230 "Location:\n"
231 " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
232 " -> PCI support (PCI [=y])\n"
233 " -> PCI access mode (<choice> [=y])\n"
234 "Selects: LIBCRC32\n"
235 "Selected by: BAR\n"
236 "-----------------------------------------------------------------\n"
237 "o The line 'Prompt:' shows the text used in the menu structure for\n"
238 " this CONFIG_ symbol\n"
239 "o The 'Defined at' line tell at what file / line number the symbol\n"
240 " is defined\n"
241 "o The 'Depends on:' line tell what symbols needs to be defined for\n"
242 " this symbol to be visible in the menu (selectable)\n"
243 "o The 'Location:' lines tell where in the menu structure this symbol\n"
244 " is located\n"
245 " A location followed by a [=y] indicate that this is a selectable\n"
246 " menu item - and current value is displayed inside brackets.\n"
247 "o The 'Selects:' line tell what symbol will be automatically\n"
248 " selected if this symbol is selected (y or m)\n"
249 "o The 'Selected by' line tell what symbol has selected this symbol\n"
Eric Andersena63d09a2003-06-30 18:14:36 +0000250 "\n"
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000251 "Only relevant lines are shown.\n"
252 "\n\n"
253 "Search examples:\n"
254 "Examples: USB => find all CONFIG_ symbols containing USB\n"
255 " ^USB => find all CONFIG_ symbols starting with USB\n"
256 " USB$ => find all CONFIG_ symbols ending with USB\n"
257 "\n";
Eric Andersenc9f20d92002-12-05 08:41:41 +0000258
259static char filename[PATH_MAX+1] = ".config";
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000260static int indent;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000261static struct termios ios_org;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000262static int rows = 0, cols = 0;
263static struct menu *current_menu;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000264static int child_count;
265static int single_menu_mode;
266
267static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
268static int item_no;
269
270static void conf(struct menu *menu);
271static void conf_choice(struct menu *menu);
272static void conf_string(struct menu *menu);
273static void conf_load(void);
274static void conf_save(void);
275static void show_textbox(const char *title, const char *text, int r, int c);
276static void show_helptext(const char *title, const char *text);
277static void show_help(struct menu *menu);
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000278static void show_file(const char *filename, const char *title, int r, int c);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000279
280static void init_wsize(void)
281{
282 struct winsize ws;
Eric Andersen72d8e442003-08-05 02:18:25 +0000283 char *env;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000284
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000285 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000286 rows = ws.ws_row;
287 cols = ws.ws_col;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000288 }
289
290 if (!rows) {
291 env = getenv("LINES");
292 if (env)
293 rows = atoi(env);
294 if (!rows)
295 rows = 24;
296 }
297 if (!cols) {
298 env = getenv("COLUMNS");
299 if (env)
300 cols = atoi(env);
301 if (!cols)
302 cols = 80;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000303 }
304
305 if (rows < 19 || cols < 80) {
306 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
307 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
308 exit(1);
309 }
310
311 rows -= 4;
312 cols -= 5;
313}
314
315static void cinit(void)
316{
317 item_no = 0;
318}
319
320static void cmake(void)
321{
322 items[item_no] = malloc(sizeof(struct dialog_list_item));
323 memset(items[item_no], 0, sizeof(struct dialog_list_item));
324 items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0;
325 items[item_no]->name = malloc(512); items[item_no]->name[0] = 0;
326 items[item_no]->namelen = 0;
327 item_no++;
328}
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000329
Eric Andersenc9f20d92002-12-05 08:41:41 +0000330static int cprint_name(const char *fmt, ...)
331{
332 va_list ap;
333 int res;
334
335 if (!item_no)
336 cmake();
337 va_start(ap, fmt);
338 res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
339 512 - items[item_no - 1]->namelen, fmt, ap);
340 if (res > 0)
341 items[item_no - 1]->namelen += res;
342 va_end(ap);
343
344 return res;
345}
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000346
Eric Andersenc9f20d92002-12-05 08:41:41 +0000347static int cprint_tag(const char *fmt, ...)
348{
349 va_list ap;
350 int res;
351
352 if (!item_no)
353 cmake();
354 va_start(ap, fmt);
355 res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
356 va_end(ap);
357
358 return res;
359}
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000360
Eric Andersenc9f20d92002-12-05 08:41:41 +0000361static void cdone(void)
362{
363 int i;
364
365 for (i = 0; i < item_no; i++) {
366 free(items[i]->tag);
367 free(items[i]->name);
368 free(items[i]);
369 }
370
371 item_no = 0;
372}
373
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000374static void get_prompt_str(struct gstr *r, struct property *prop)
375{
376 int i, j;
377 struct menu *submenu[8], *menu;
378
379 str_printf(r, "Prompt: %s\n", prop->text);
380 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
381 prop->menu->lineno);
382 if (!expr_is_yes(prop->visible.expr)) {
383 str_append(r, " Depends on: ");
384 expr_gstr_print(prop->visible.expr, r);
385 str_append(r, "\n");
386 }
387 menu = prop->menu->parent;
388 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
389 submenu[i++] = menu;
390 if (i > 0) {
391 str_printf(r, " Location:\n");
392 for (j = 4; --i >= 0; j += 2) {
393 menu = submenu[i];
394 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
395 if (menu->sym) {
396 str_printf(r, " (%s [=%s])", menu->sym->name ?
397 menu->sym->name : "<choice>",
398 sym_get_string_value(menu->sym));
399 }
400 str_append(r, "\n");
401 }
402 }
403}
404
405static void get_symbol_str(struct gstr *r, struct symbol *sym)
406{
407 bool hit;
408 struct property *prop;
409
410 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
411 sym_get_string_value(sym));
412 for_all_prompts(sym, prop)
413 get_prompt_str(r, prop);
414 hit = false;
415 for_all_properties(sym, prop, P_SELECT) {
416 if (!hit) {
417 str_append(r, " Selects: ");
418 hit = true;
419 } else
420 str_printf(r, " && ");
421 expr_gstr_print(prop->expr, r);
422 }
423 if (hit)
424 str_append(r, "\n");
425 if (sym->rev_dep.expr) {
426 str_append(r, " Selected by: ");
427 expr_gstr_print(sym->rev_dep.expr, r);
428 str_append(r, "\n");
429 }
430 str_append(r, "\n\n");
431}
432
433static struct gstr get_relations_str(struct symbol **sym_arr)
434{
435 struct symbol *sym;
436 struct gstr res = str_new();
437 int i;
438
439 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
440 get_symbol_str(&res, sym);
441 if (!i)
442 str_append(&res, "No matches found.\n");
443 return res;
444}
445
446static void search_conf(void)
447{
448 struct symbol **sym_arr;
449 struct gstr res;
450
451again:
452 switch (dialog_inputbox("Search Configuration Parameter",
453 "Enter Keyword", 10, 75,
454 NULL)) {
455 case 0:
456 break;
457 case 1:
458 show_helptext("Search Configuration", search_help);
459 goto again;
460 default:
461 return;
462 }
463
464 sym_arr = sym_re_search(dialog_input_result);
465 res = get_relations_str(sym_arr);
466 free(sym_arr);
467 show_textbox("Search Results", str_get(&res), 0, 0);
468 str_free(&res);
469}
470
Eric Andersenc9f20d92002-12-05 08:41:41 +0000471static void build_conf(struct menu *menu)
472{
473 struct symbol *sym;
474 struct property *prop;
475 struct menu *child;
476 int type, tmp, doint = 2;
477 tristate val;
478 char ch;
479
480 if (!menu_is_visible(menu))
481 return;
482
483 sym = menu->sym;
484 prop = menu->prompt;
485 if (!sym) {
486 if (prop && menu != current_menu) {
487 const char *prompt = menu_get_prompt(menu);
488 switch (prop->type) {
489 case P_MENU:
490 child_count++;
491 cmake();
492 cprint_tag("m%p", menu);
493
494 if (single_menu_mode) {
495 cprint_name("%s%*c%s",
496 menu->data ? "-->" : "++>",
497 indent + 1, ' ', prompt);
498 } else {
Eric Andersen72d8e442003-08-05 02:18:25 +0000499 cprint_name(" %*c%s --->", indent + 1, ' ', prompt);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000500 }
501
502 if (single_menu_mode && menu->data)
503 goto conf_childs;
504 return;
505 default:
506 if (prompt) {
507 child_count++;
508 cmake();
509 cprint_tag(":%p", menu);
510 cprint_name("---%*c%s", indent + 1, ' ', prompt);
511 }
512 }
513 } else
514 doint = 0;
515 goto conf_childs;
516 }
517
518 cmake();
519 type = sym_get_type(sym);
520 if (sym_is_choice(sym)) {
521 struct symbol *def_sym = sym_get_choice_value(sym);
522 struct menu *def_menu = NULL;
523
524 child_count++;
525 for (child = menu->list; child; child = child->next) {
526 if (menu_is_visible(child) && child->sym == def_sym)
527 def_menu = child;
528 }
529
530 val = sym_get_tristate_value(sym);
531 if (sym_is_changable(sym)) {
532 cprint_tag("t%p", menu);
533 switch (type) {
534 case S_BOOLEAN:
535 cprint_name("[%c]", val == no ? ' ' : '*');
536 break;
537 case S_TRISTATE:
538 switch (val) {
539 case yes: ch = '*'; break;
540 case mod: ch = 'M'; break;
541 default: ch = ' '; break;
542 }
543 cprint_name("<%c>", ch);
544 break;
545 }
546 } else {
547 cprint_tag("%c%p", def_menu ? 't' : ':', menu);
548 cprint_name(" ");
549 }
550
551 cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
552 if (val == yes) {
553 if (def_menu) {
554 cprint_name(" (%s)", menu_get_prompt(def_menu));
555 cprint_name(" --->");
556 if (def_menu->list) {
557 indent += 2;
558 build_conf(def_menu);
559 indent -= 2;
560 }
561 }
562 return;
563 }
564 } else {
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000565 if (menu == current_menu) {
566 cprint_tag(":%p", menu);
567 cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
568 goto conf_childs;
569 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000570 child_count++;
571 val = sym_get_tristate_value(sym);
572 if (sym_is_choice_value(sym) && val == yes) {
573 cprint_tag(":%p", menu);
574 cprint_name(" ");
575 } else {
576 switch (type) {
577 case S_BOOLEAN:
578 cprint_tag("t%p", menu);
Eric Andersen72d8e442003-08-05 02:18:25 +0000579 if (sym_is_changable(sym))
580 cprint_name("[%c]", val == no ? ' ' : '*');
581 else
582 cprint_name("---");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000583 break;
584 case S_TRISTATE:
585 cprint_tag("t%p", menu);
586 switch (val) {
587 case yes: ch = '*'; break;
588 case mod: ch = 'M'; break;
589 default: ch = ' '; break;
590 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000591 if (sym_is_changable(sym))
592 cprint_name("<%c>", ch);
593 else
594 cprint_name("---");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000595 break;
596 default:
597 cprint_tag("s%p", menu);
598 tmp = cprint_name("(%s)", sym_get_string_value(sym));
599 tmp = indent - tmp + 4;
600 if (tmp < 0)
601 tmp = 0;
602 cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
Eric Andersen72d8e442003-08-05 02:18:25 +0000603 (sym_has_value(sym) || !sym_is_changable(sym)) ?
604 "" : " (NEW)");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000605 goto conf_childs;
606 }
607 }
608 cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
Eric Andersen72d8e442003-08-05 02:18:25 +0000609 (sym_has_value(sym) || !sym_is_changable(sym)) ?
610 "" : " (NEW)");
611 if (menu->prompt->type == P_MENU) {
612 cprint_name(" --->");
613 return;
614 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000615 }
616
617conf_childs:
618 indent += doint;
619 for (child = menu->list; child; child = child->next)
620 build_conf(child);
621 indent -= doint;
622}
623
624static void conf(struct menu *menu)
625{
626 struct dialog_list_item *active_item = NULL;
627 struct menu *submenu;
628 const char *prompt = menu_get_prompt(menu);
629 struct symbol *sym;
630 char active_entry[40];
631 int stat, type;
632
633 unlink("lxdialog.scrltmp");
634 active_entry[0] = 0;
635 while (1) {
636 indent = 0;
637 child_count = 0;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000638 current_menu = menu;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000639 cdone(); cinit();
640 build_conf(menu);
641 if (!child_count)
642 break;
643 if (menu == &rootmenu) {
644 cmake(); cprint_tag(":"); cprint_name("--- ");
645 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
646 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
647 }
648 dialog_clear();
649 stat = dialog_menu(prompt ? prompt : "Main Menu",
650 menu_instructions, rows, cols, rows - 10,
651 active_entry, item_no, items);
652 if (stat < 0)
653 return;
654
655 if (stat == 1 || stat == 255)
656 break;
657
658 active_item = first_sel_item(item_no, items);
659 if (!active_item)
660 continue;
661 active_item->selected = 0;
662 strncpy(active_entry, active_item->tag, sizeof(active_entry));
663 active_entry[sizeof(active_entry)-1] = 0;
664 type = active_entry[0];
665 if (!type)
666 continue;
667
668 sym = NULL;
669 submenu = NULL;
670 if (sscanf(active_entry + 1, "%p", &submenu) == 1)
671 sym = submenu->sym;
672
673 switch (stat) {
674 case 0:
675 switch (type) {
676 case 'm':
677 if (single_menu_mode)
Eric Andersen72d8e442003-08-05 02:18:25 +0000678 submenu->data = (void *) (long) !submenu->data;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000679 else
680 conf(submenu);
681 break;
682 case 't':
683 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
684 conf_choice(submenu);
Eric Andersen72d8e442003-08-05 02:18:25 +0000685 else if (submenu->prompt->type == P_MENU)
686 conf(submenu);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000687 break;
688 case 's':
689 conf_string(submenu);
690 break;
691 case 'L':
692 conf_load();
693 break;
694 case 'S':
695 conf_save();
696 break;
697 }
698 break;
699 case 2:
700 if (sym)
701 show_help(submenu);
702 else
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000703 show_helptext("README", mconf_readme);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000704 break;
705 case 3:
706 if (type == 't') {
707 if (sym_set_tristate_value(sym, yes))
708 break;
709 if (sym_set_tristate_value(sym, mod))
710 show_textbox(NULL, setmod_text, 6, 74);
711 }
712 break;
713 case 4:
714 if (type == 't')
715 sym_set_tristate_value(sym, no);
716 break;
717 case 5:
718 if (type == 't')
719 sym_set_tristate_value(sym, mod);
720 break;
721 case 6:
722 if (type == 't')
723 sym_toggle_tristate_value(sym);
724 else if (type == 'm')
725 conf(submenu);
726 break;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000727 case 7:
728 search_conf();
729 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000730 }
731 }
732}
733
734static void show_textbox(const char *title, const char *text, int r, int c)
735{
736 int fd;
737
738 fd = creat(".help.tmp", 0777);
739 write(fd, text, strlen(text));
740 close(fd);
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000741 show_file(".help.tmp", title, r, c);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000742 unlink(".help.tmp");
743}
744
745static void show_helptext(const char *title, const char *text)
746{
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000747 show_textbox(title, text, 0, 0);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000748}
749
750static void show_help(struct menu *menu)
751{
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000752 struct gstr help = str_new();
Eric Andersenc9f20d92002-12-05 08:41:41 +0000753 struct symbol *sym = menu->sym;
754
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000755 if (sym->help)
756 {
757 if (sym->name) {
758 str_printf(&help, "%s:\n\n", sym->name);
759 str_append(&help, sym->help);
760 str_append(&help, "\n");
761 }
762 } else {
763 str_append(&help, nohelp_text);
764 }
765 get_symbol_str(&help, sym);
766 show_helptext(menu_get_prompt(menu), str_get(&help));
767 str_free(&help);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000768}
769
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000770static void show_file(const char *filename, const char *title, int r, int c)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000771{
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000772 while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
773 ;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000774}
775
776static void conf_choice(struct menu *menu)
777{
778 const char *prompt = menu_get_prompt(menu);
779 struct menu *child;
780 struct symbol *active;
781
Eric Andersen837f0582004-07-15 06:01:05 +0000782 active = sym_get_choice_value(menu->sym);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000783 while (1) {
784 current_menu = menu;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000785 cdone(); cinit();
786 for (child = menu->list; child; child = child->next) {
787 if (!menu_is_visible(child))
788 continue;
789 cmake();
790 cprint_tag("%p", child);
791 cprint_name("%s", menu_get_prompt(child));
Eric Andersen837f0582004-07-15 06:01:05 +0000792 if (child->sym == sym_get_choice_value(menu->sym))
793 items[item_no - 1]->selected = 1; /* ON */
794 else if (child->sym == active)
795 items[item_no - 1]->selected = 2; /* SELECTED */
796 else
797 items[item_no - 1]->selected = 0; /* OFF */
Eric Andersenc9f20d92002-12-05 08:41:41 +0000798 }
799
800 switch (dialog_checklist(prompt ? prompt : "Main Menu",
801 radiolist_instructions, 15, 70, 6,
802 item_no, items, FLAG_RADIO)) {
803 case 0:
Eric Andersen837f0582004-07-15 06:01:05 +0000804 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000805 break;
Eric Andersen837f0582004-07-15 06:01:05 +0000806 sym_set_tristate_value(child->sym, yes);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000807 return;
808 case 1:
Eric Andersen837f0582004-07-15 06:01:05 +0000809 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
810 show_help(child);
811 active = child->sym;
812 } else
813 show_help(menu);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000814 break;
815 case 255:
816 return;
817 }
818 }
819}
820
821static void conf_string(struct menu *menu)
822{
823 const char *prompt = menu_get_prompt(menu);
824
825 while (1) {
826 char *heading;
827
828 switch (sym_get_type(menu->sym)) {
829 case S_INT:
830 heading = (char *) inputbox_instructions_int;
831 break;
832 case S_HEX:
833 heading = (char *) inputbox_instructions_hex;
834 break;
835 case S_STRING:
836 heading = (char *) inputbox_instructions_string;
837 break;
838 default:
839 heading = "Internal mconf error!";
840 /* panic? */;
841 }
842
843 switch (dialog_inputbox(prompt ? prompt : "Main Menu",
844 heading, 10, 75,
845 sym_get_string_value(menu->sym))) {
846 case 0:
847 if (sym_set_string_value(menu->sym, dialog_input_result))
848 return;
849 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
850 break;
851 case 1:
852 show_help(menu);
853 break;
854 case 255:
855 return;
856 }
857 }
858}
859
860static void conf_load(void)
861{
862 while (1) {
863 switch (dialog_inputbox(NULL, load_config_text, 11, 55,
864 filename)) {
865 case 0:
866 if (!dialog_input_result[0])
867 return;
868 if (!conf_read(dialog_input_result))
869 return;
870 show_textbox(NULL, "File does not exist!", 5, 38);
871 break;
872 case 1:
873 show_helptext("Load Alternate Configuration", load_config_help);
874 break;
875 case 255:
876 return;
877 }
878 }
879}
880
881static void conf_save(void)
882{
883 while (1) {
884 switch (dialog_inputbox(NULL, save_config_text, 11, 55,
885 filename)) {
886 case 0:
887 if (!dialog_input_result[0])
888 return;
889 if (!conf_write(dialog_input_result))
890 return;
891 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
892 break;
893 case 1:
894 show_helptext("Save Alternate Configuration", save_config_help);
895 break;
896 case 255:
897 return;
898 }
899 }
900}
901
902static void conf_cleanup(void)
903{
904 tcsetattr(1, TCSAFLUSH, &ios_org);
905 unlink(".help.tmp");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000906}
907
908static void winch_handler(int sig)
909{
910 struct winsize ws;
911
912 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
913 rows = 24;
914 cols = 80;
915 } else {
916 rows = ws.ws_row;
917 cols = ws.ws_col;
918 }
919
920 if (rows < 19 || cols < 80) {
921 end_dialog();
922 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
923 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
924 exit(1);
925 }
926
927 rows -= 4;
928 cols -= 5;
929
930}
931
932int main(int ac, char **av)
933{
Eric Andersenc9f20d92002-12-05 08:41:41 +0000934 struct symbol *sym;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000935 char *mode;
936 int stat;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000937
938 conf_parse(av[1]);
939 conf_read(NULL);
940
Eric Andersenc9f20d92002-12-05 08:41:41 +0000941 sym = sym_lookup("VERSION", 0);
942 sym_calc_value(sym);
Eric Andersen72d8e442003-08-05 02:18:25 +0000943 snprintf(menu_backtitle, 128, "BusyBox v%s Configuration",
Eric Andersenc9f20d92002-12-05 08:41:41 +0000944 sym_get_string_value(sym));
945
946 mode = getenv("MENUCONFIG_MODE");
947 if (mode) {
948 if (!strcasecmp(mode, "single_menu"))
949 single_menu_mode = 1;
950 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000951
Eric Andersenc9f20d92002-12-05 08:41:41 +0000952 tcgetattr(1, &ios_org);
953 atexit(conf_cleanup);
954 init_wsize();
955 init_dialog();
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000956 signal(SIGWINCH, winch_handler);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000957 conf(&rootmenu);
958 end_dialog();
959
960 /* Restart dialog to act more like when lxdialog was still separate */
961 init_dialog();
962 do {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000963 stat = dialog_yesno(NULL,
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +0000964 "Do you wish to save your new BusyBox configuration?", 5, 60);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000965 } while (stat < 0);
966 end_dialog();
967
968 if (stat == 0) {
969 conf_write(NULL);
970 printf("\n\n"
971 "*** End of BusyBox configuration.\n"
972 "*** Check the top-level Makefile for additional configuration options.\n\n");
973 } else
974 printf("\n\nYour BusyBox configuration changes were NOT saved.\n\n");
975
976 return 0;
977}