source: MondoRescue/branches/stable/mindi-busybox/scripts/config/mconf.c@ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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