Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / busybox / scripts / kconfig / mconf.c
blob006d03708855ecfb181a6c68e363d9053c211b49
1 /*
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 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9 */
11 #define _XOPEN_SOURCE 700
12 /* On Darwin, this may be needed to get SIGWINCH: */
13 #define _DARWIN_C_SOURCE 1
15 #include <sys/ioctl.h>
16 #include <sys/wait.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <limits.h>
21 #include <signal.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h> /* for strcasecmp */
26 #include <termios.h>
27 #include <unistd.h>
28 #include <locale.h>
30 #define LKC_DIRECT_LINK
31 #include "lkc.h"
33 static char menu_backtitle[128];
34 static const char mconf_readme[] = N_(
35 "Overview\n"
36 "--------\n"
37 "Some features may be built directly into busybox.\n"
38 "Some may be made into standalone applets. Some features\n"
39 "may be completely removed altogether. There are also certain\n"
40 "parameters which are not really features, but must be\n"
41 "entered in as decimal or hexadecimal numbers or possibly text.\n"
42 "\n"
43 "Menu items beginning with [*], <M> or [ ] represent features\n"
44 "configured to be built in, modularized or removed respectively.\n"
45 "Pointed brackets <> represent module capable features.\n"
46 "\n"
47 "To change any of these features, highlight it with the cursor\n"
48 "keys and press <Y> to build it in, <M> to make it a module or\n"
49 "<N> to removed it. You may also press the <Space Bar> to cycle\n"
50 "through the available options (ie. Y->N->M->Y).\n"
51 "\n"
52 "Some additional keyboard hints:\n"
53 "\n"
54 "Menus\n"
55 "----------\n"
56 "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
57 " you wish to change or submenu wish to select and press <Enter>.\n"
58 " Submenus are designated by \"--->\".\n"
59 "\n"
60 " Shortcut: Press the option's highlighted letter (hotkey).\n"
61 " Pressing a hotkey more than once will sequence\n"
62 " through all visible items which use that hotkey.\n"
63 "\n"
64 " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
65 " unseen options into view.\n"
66 "\n"
67 "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
68 " and press <ENTER>.\n"
69 "\n"
70 " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
71 " using those letters. You may press a single <ESC>, but\n"
72 " there is a delayed response which you may find annoying.\n"
73 "\n"
74 " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
75 " <Exit> and <Help>\n"
76 "\n"
77 "o To get help with an item, use the cursor keys to highlight <Help>\n"
78 " and Press <ENTER>.\n"
79 "\n"
80 " Shortcut: Press <H> or <?>.\n"
81 "\n"
82 "\n"
83 "Radiolists (Choice lists)\n"
84 "-----------\n"
85 "o Use the cursor keys to select the option you wish to set and press\n"
86 " <S> or the <SPACE BAR>.\n"
87 "\n"
88 " Shortcut: Press the first letter of the option you wish to set then\n"
89 " press <S> or <SPACE BAR>.\n"
90 "\n"
91 "o To see available help for the item, use the cursor keys to highlight\n"
92 " <Help> and Press <ENTER>.\n"
93 "\n"
94 " Shortcut: Press <H> or <?>.\n"
95 "\n"
96 " Also, the <TAB> and cursor keys will cycle between <Select> and\n"
97 " <Help>\n"
98 "\n"
99 "\n"
100 "Data Entry\n"
101 "-----------\n"
102 "o Enter the requested information and press <ENTER>\n"
103 " If you are entering hexadecimal values, it is not necessary to\n"
104 " add the '0x' prefix to the entry.\n"
105 "\n"
106 "o For help, use the <TAB> or cursor keys to highlight the help option\n"
107 " and press <ENTER>. You can try <TAB><H> as well.\n"
108 "\n"
109 "\n"
110 "Text Box (Help Window)\n"
111 "--------\n"
112 "o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
113 " keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
114 " who are familiar with less and lynx.\n"
115 "\n"
116 "o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
117 "\n"
118 "\n"
119 "Alternate Configuration Files\n"
120 "-----------------------------\n"
121 "Menuconfig supports the use of alternate configuration files for\n"
122 "those who, for various reasons, find it necessary to switch\n"
123 "between different configurations.\n"
124 "\n"
125 "At the end of the main menu you will find two options. One is\n"
126 "for saving the current configuration to a file of your choosing.\n"
127 "The other option is for loading a previously saved alternate\n"
128 "configuration.\n"
129 "\n"
130 "Even if you don't use alternate configuration files, but you\n"
131 "find during a Menuconfig session that you have completely messed\n"
132 "up your settings, you may use the \"Load Alternate...\" option to\n"
133 "restore your previously saved settings from \".config\" without\n"
134 "restarting Menuconfig.\n"
135 "\n"
136 "Other information\n"
137 "-----------------\n"
138 "If you use Menuconfig in an XTERM window make sure you have your\n"
139 "$TERM variable set to point to a xterm definition which supports color.\n"
140 "Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
141 "display correctly in a RXVT window because rxvt displays only one\n"
142 "intensity of color, bright.\n"
143 "\n"
144 "Menuconfig will display larger menus on screens or xterms which are\n"
145 "set to display more than the standard 25 row by 80 column geometry.\n"
146 "In order for this to work, the \"stty size\" command must be able to\n"
147 "display the screen's current row and column geometry. I STRONGLY\n"
148 "RECOMMEND that you make sure you do NOT have the shell variables\n"
149 "LINES and COLUMNS exported into your environment. Some distributions\n"
150 "export those variables via /etc/profile. Some ncurses programs can\n"
151 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
152 "the true screen size.\n"
153 "\n"
154 "Optional personality available\n"
155 "------------------------------\n"
156 "If you prefer to have all of the options listed in a single\n"
157 "menu, rather than the default multimenu hierarchy, run the menuconfig\n"
158 "with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
159 "\n"
160 "make MENUCONFIG_MODE=single_menu menuconfig\n"
161 "\n"
162 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
163 "is already unrolled.\n"
164 "\n"
165 "Note that this mode can eventually be a little more CPU expensive\n"
166 "(especially with a larger number of unrolled categories) than the\n"
167 "default mode.\n"),
168 menu_instructions[] = N_(
169 "Arrow keys navigate the menu. "
170 "<Enter> selects submenus --->. "
171 "Highlighted letters are hotkeys. "
172 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
173 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
174 "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
175 radiolist_instructions[] = N_(
176 "Use the arrow keys to navigate this window or "
177 "press the hotkey of the item you wish to select "
178 "followed by the <SPACE BAR>. "
179 "Press <?> for additional information about this option."),
180 inputbox_instructions_int[] = N_(
181 "Please enter a decimal value. "
182 "Fractions will not be accepted. "
183 "Use the <TAB> key to move from the input field to the buttons below it."),
184 inputbox_instructions_hex[] = N_(
185 "Please enter a hexadecimal value. "
186 "Use the <TAB> key to move from the input field to the buttons below it."),
187 inputbox_instructions_string[] = N_(
188 "Please enter a string value. "
189 "Use the <TAB> key to move from the input field to the buttons below it."),
190 setmod_text[] = N_(
191 "This feature depends on another which has been configured as a module.\n"
192 "As a result, this feature will be built as a module."),
193 nohelp_text[] = N_(
194 "There is no help available for this option.\n"),
195 load_config_text[] = N_(
196 "Enter the name of the configuration file you wish to load. "
197 "Accept the name shown to restore the configuration you "
198 "last retrieved. Leave blank to abort."),
199 load_config_help[] = N_(
200 "\n"
201 "For various reasons, one may wish to keep several different\n"
202 "configurations available on a single machine.\n"
203 "\n"
204 "If you have saved a previous configuration in a file other than\n"
205 "default, entering the name of the file here will allow you\n"
206 "to modify that configuration.\n"
207 "\n"
208 "If you are uncertain, then you have probably never used alternate\n"
209 "configuration files. You should therefor leave this blank to abort.\n"),
210 save_config_text[] = N_(
211 "Enter a filename to which this configuration should be saved "
212 "as an alternate. Leave blank to abort."),
213 save_config_help[] = N_(
214 "\n"
215 "For various reasons, one may wish to keep different\n"
216 "configurations available on a single machine.\n"
217 "\n"
218 "Entering a file name here will allow you to later retrieve, modify\n"
219 "and use the current configuration as an alternate to whatever\n"
220 "configuration options you have selected at that time.\n"
221 "\n"
222 "If you are uncertain what all this means then you should probably\n"
223 "leave this blank.\n"),
224 search_help[] = N_(
225 "\n"
226 "Search for CONFIG_ symbols and display their relations.\n"
227 "Regular expressions are allowed.\n"
228 "Example: search for \"^FOO\"\n"
229 "Result:\n"
230 "-----------------------------------------------------------------\n"
231 "Symbol: FOO [=m]\n"
232 "Prompt: Foo bus is used to drive the bar HW\n"
233 "Defined at drivers/pci/Kconfig:47\n"
234 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
235 "Location:\n"
236 " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
237 " -> PCI support (PCI [=y])\n"
238 " -> PCI access mode (<choice> [=y])\n"
239 "Selects: LIBCRC32\n"
240 "Selected by: BAR\n"
241 "-----------------------------------------------------------------\n"
242 "o The line 'Prompt:' shows the text used in the menu structure for\n"
243 " this CONFIG_ symbol\n"
244 "o The 'Defined at' line tell at what file / line number the symbol\n"
245 " is defined\n"
246 "o The 'Depends on:' line tell what symbols needs to be defined for\n"
247 " this symbol to be visible in the menu (selectable)\n"
248 "o The 'Location:' lines tell where in the menu structure this symbol\n"
249 " is located\n"
250 " A location followed by a [=y] indicate that this is a selectable\n"
251 " menu item - and current value is displayed inside brackets.\n"
252 "o The 'Selects:' line tell what symbol will be automatically\n"
253 " selected if this symbol is selected (y or m)\n"
254 "o The 'Selected by' line tell what symbol has selected this symbol\n"
255 "\n"
256 "Only relevant lines are shown.\n"
257 "\n\n"
258 "Search examples:\n"
259 "Examples: USB => find all CONFIG_ symbols containing USB\n"
260 " ^USB => find all CONFIG_ symbols starting with USB\n"
261 " USB$ => find all CONFIG_ symbols ending with USB\n"
262 "\n");
264 static char buf[4096*10], *bufptr = buf;
265 static char input_buf[4096];
266 static const char filename[] = ".config";
267 static char *args[1024], **argptr = args;
268 static int indent;
269 static struct termios ios_org;
270 static int rows = 0, cols = 0;
271 static struct menu *current_menu;
272 static int child_count;
273 static int do_resize;
274 static int single_menu_mode;
276 static void conf(struct menu *menu);
277 static void conf_choice(struct menu *menu);
278 static void conf_string(struct menu *menu);
279 static void conf_load(void);
280 static void conf_save(void);
281 static void show_textbox(const char *title, const char *text, int r, int c);
282 static void show_helptext(const char *title, const char *text);
283 static void show_help(struct menu *menu);
284 static void show_file(const char *filename, const char *title, int r, int c);
286 static void cprint_init(void);
287 static int cprint1(const char *fmt, ...);
288 static void cprint_done(void);
289 static int cprint(const char *fmt, ...);
291 static void init_wsize(void)
293 struct winsize ws;
294 char *env;
296 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
297 rows = ws.ws_row;
298 cols = ws.ws_col;
301 if (!rows) {
302 env = getenv("LINES");
303 if (env)
304 rows = atoi(env);
305 if (!rows)
306 rows = 24;
308 if (!cols) {
309 env = getenv("COLUMNS");
310 if (env)
311 cols = atoi(env);
312 if (!cols)
313 cols = 80;
316 if (rows < 19 || cols < 80) {
317 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
318 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
319 exit(1);
322 rows -= 4;
323 cols -= 5;
326 static void cprint_init(void)
328 bufptr = buf;
329 argptr = args;
330 memset(args, 0, sizeof(args));
331 indent = 0;
332 child_count = 0;
333 cprint("./scripts/kconfig/lxdialog/lxdialog");
334 cprint("--backtitle");
335 cprint(menu_backtitle);
338 static int cprint1(const char *fmt, ...)
340 va_list ap;
341 int res;
343 if (!*argptr)
344 *argptr = bufptr;
345 va_start(ap, fmt);
346 res = vsprintf(bufptr, fmt, ap);
347 va_end(ap);
348 bufptr += res;
350 return res;
353 static void cprint_done(void)
355 *bufptr++ = 0;
356 argptr++;
359 static int cprint(const char *fmt, ...)
361 va_list ap;
362 int res;
364 *argptr++ = bufptr;
365 va_start(ap, fmt);
366 res = vsprintf(bufptr, fmt, ap);
367 va_end(ap);
368 bufptr += res;
369 *bufptr++ = 0;
371 return res;
374 static void get_prompt_str(struct gstr *r, struct property *prop)
376 int i, j;
377 struct menu *submenu[8], *menu;
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");
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));
400 str_append(r, "\n");
405 static void get_symbol_str(struct gstr *r, struct symbol *sym)
407 bool hit;
408 struct property *prop;
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);
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");
430 str_append(r, "\n\n");
433 static struct gstr get_relations_str(struct symbol **sym_arr)
435 struct symbol *sym;
436 struct gstr res = str_new();
437 int i;
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;
446 pid_t pid;
448 #ifdef SIGWINCH
449 static void winch_handler(int sig)
451 if (!do_resize) {
452 kill(pid, SIGINT);
453 do_resize = 1;
456 #endif
458 static int exec_conf(void)
460 int pipefd[2], stat, size;
461 sigset_t sset, osset;
463 sigemptyset(&sset);
464 sigaddset(&sset, SIGINT);
465 sigprocmask(SIG_BLOCK, &sset, &osset);
467 signal(SIGINT, SIG_DFL);
469 #ifdef SIGWINCH
471 struct sigaction sa;
472 sa.sa_handler = winch_handler;
473 sigemptyset(&sa.sa_mask);
474 sa.sa_flags = SA_RESTART;
475 sigaction(SIGWINCH, &sa, NULL);
477 #endif
479 *argptr++ = NULL;
481 pipe(pipefd);
482 pid = fork();
483 if (pid == 0) {
484 sigprocmask(SIG_SETMASK, &osset, NULL);
485 dup2(pipefd[1], 2);
486 close(pipefd[0]);
487 close(pipefd[1]);
488 execv(args[0], args);
489 _exit(EXIT_FAILURE);
492 close(pipefd[1]);
493 bufptr = input_buf;
494 while (1) {
495 size = input_buf + sizeof(input_buf) - bufptr;
496 size = read(pipefd[0], bufptr, size);
497 if (size <= 0) {
498 if (size < 0) {
499 if (errno == EINTR || errno == EAGAIN)
500 continue;
501 perror("read");
503 break;
505 bufptr += size;
507 *bufptr++ = 0;
508 close(pipefd[0]);
509 waitpid(pid, &stat, 0);
511 if (do_resize) {
512 init_wsize();
513 do_resize = 0;
514 sigprocmask(SIG_SETMASK, &osset, NULL);
515 return -1;
517 if (WIFSIGNALED(stat)) {
518 printf("\finterrupted(%d)\n", WTERMSIG(stat));
519 exit(1);
521 #if 0
522 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
523 sleep(1);
524 #endif
525 sigpending(&sset);
526 if (sigismember(&sset, SIGINT)) {
527 printf("\finterrupted\n");
528 exit(1);
530 sigprocmask(SIG_SETMASK, &osset, NULL);
532 return WEXITSTATUS(stat);
535 static void search_conf(void)
537 struct symbol **sym_arr;
538 int stat;
539 struct gstr res;
541 again:
542 cprint_init();
543 cprint("--title");
544 cprint(_("Search Configuration Parameter"));
545 cprint("--inputbox");
546 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
547 cprint("10");
548 cprint("75");
549 cprint("");
550 stat = exec_conf();
551 if (stat < 0)
552 goto again;
553 switch (stat) {
554 case 0:
555 break;
556 case 1:
557 show_helptext(_("Search Configuration"), search_help);
558 goto again;
559 default:
560 return;
563 sym_arr = sym_re_search(input_buf);
564 res = get_relations_str(sym_arr);
565 free(sym_arr);
566 show_textbox(_("Search Results"), str_get(&res), 0, 0);
567 str_free(&res);
570 static void build_conf(struct menu *menu)
572 struct symbol *sym;
573 struct property *prop;
574 struct menu *child;
575 int type, tmp, doint = 2;
576 tristate val;
577 char ch;
579 if (!menu_is_visible(menu))
580 return;
582 sym = menu->sym;
583 prop = menu->prompt;
584 if (!sym) {
585 if (prop && menu != current_menu) {
586 const char *prompt = menu_get_prompt(menu);
587 switch (prop->type) {
588 case P_MENU:
589 child_count++;
590 cprint("m%p", menu);
592 if (single_menu_mode) {
593 cprint1("%s%*c%s",
594 menu->data ? "-->" : "++>",
595 indent + 1, ' ', prompt);
596 } else
597 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
599 cprint_done();
600 if (single_menu_mode && menu->data)
601 goto conf_childs;
602 return;
603 default:
604 if (prompt) {
605 child_count++;
606 cprint(":%p", menu);
607 cprint("---%*c%s", indent + 1, ' ', prompt);
610 } else
611 doint = 0;
612 goto conf_childs;
615 type = sym_get_type(sym);
616 if (sym_is_choice(sym)) {
617 struct symbol *def_sym = sym_get_choice_value(sym);
618 struct menu *def_menu = NULL;
620 child_count++;
621 for (child = menu->list; child; child = child->next) {
622 if (menu_is_visible(child) && child->sym == def_sym)
623 def_menu = child;
626 val = sym_get_tristate_value(sym);
627 if (sym_is_changable(sym)) {
628 cprint("t%p", menu);
629 switch (type) {
630 case S_BOOLEAN:
631 cprint1("[%c]", val == no ? ' ' : '*');
632 break;
633 case S_TRISTATE:
634 switch (val) {
635 case yes: ch = '*'; break;
636 case mod: ch = 'M'; break;
637 default: ch = ' '; break;
639 cprint1("<%c>", ch);
640 break;
642 } else {
643 cprint("%c%p", def_menu ? 't' : ':', menu);
644 cprint1(" ");
647 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
648 if (val == yes) {
649 if (def_menu) {
650 cprint1(" (%s)", menu_get_prompt(def_menu));
651 cprint1(" --->");
652 cprint_done();
653 if (def_menu->list) {
654 indent += 2;
655 build_conf(def_menu);
656 indent -= 2;
658 } else
659 cprint_done();
660 return;
662 cprint_done();
663 } else {
664 if (menu == current_menu) {
665 cprint(":%p", menu);
666 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
667 goto conf_childs;
669 child_count++;
670 val = sym_get_tristate_value(sym);
671 if (sym_is_choice_value(sym) && val == yes) {
672 cprint(":%p", menu);
673 cprint1(" ");
674 } else {
675 switch (type) {
676 case S_BOOLEAN:
677 cprint("t%p", menu);
678 if (sym_is_changable(sym))
679 cprint1("[%c]", val == no ? ' ' : '*');
680 else
681 cprint1("---");
682 break;
683 case S_TRISTATE:
684 cprint("t%p", menu);
685 switch (val) {
686 case yes: ch = '*'; break;
687 case mod: ch = 'M'; break;
688 default: ch = ' '; break;
690 if (sym_is_changable(sym))
691 cprint1("<%c>", ch);
692 else
693 cprint1("---");
694 break;
695 default:
696 cprint("s%p", menu);
697 tmp = cprint1("(%s)", sym_get_string_value(sym));
698 tmp = indent - tmp + 4;
699 if (tmp < 0)
700 tmp = 0;
701 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
702 (sym_has_value(sym) || !sym_is_changable(sym)) ?
703 "" : " (NEW)");
704 cprint_done();
705 goto conf_childs;
708 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
709 (sym_has_value(sym) || !sym_is_changable(sym)) ?
710 "" : " (NEW)");
711 if (menu->prompt->type == P_MENU) {
712 cprint1(" --->");
713 cprint_done();
714 return;
716 cprint_done();
719 conf_childs:
720 indent += doint;
721 for (child = menu->list; child; child = child->next)
722 build_conf(child);
723 indent -= doint;
726 static void conf(struct menu *menu)
728 struct menu *submenu;
729 const char *prompt = menu_get_prompt(menu);
730 struct symbol *sym;
731 char active_entry[40];
732 int stat, type, i;
734 unlink("lxdialog.scrltmp");
735 active_entry[0] = 0;
736 while (1) {
737 cprint_init();
738 cprint("--title");
739 cprint("%s", prompt ? prompt : _("Main Menu"));
740 cprint("--menu");
741 cprint(_(menu_instructions));
742 cprint("%d", rows);
743 cprint("%d", cols);
744 cprint("%d", rows - 10);
745 cprint("%s", active_entry);
746 current_menu = menu;
747 build_conf(menu);
748 if (!child_count)
749 break;
750 if (menu == &rootmenu) {
751 cprint(":");
752 cprint("--- ");
753 cprint("L");
754 cprint(_(" Load an Alternate Configuration File"));
755 cprint("S");
756 cprint(_(" Save Configuration to an Alternate File"));
758 stat = exec_conf();
759 if (stat < 0)
760 continue;
762 if (stat == 1 || stat == 255)
763 break;
765 type = input_buf[0];
766 if (!type)
767 continue;
769 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
771 if (i >= sizeof(active_entry))
772 i = sizeof(active_entry) - 1;
773 input_buf[i] = 0;
774 strcpy(active_entry, input_buf);
776 sym = NULL;
777 submenu = NULL;
778 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
779 sym = submenu->sym;
781 switch (stat) {
782 case 0:
783 switch (type) {
784 case 'm':
785 if (single_menu_mode)
786 submenu->data = (void *) (long) !submenu->data;
787 else
788 conf(submenu);
789 break;
790 case 't':
791 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
792 conf_choice(submenu);
793 else if (submenu->prompt->type == P_MENU)
794 conf(submenu);
795 break;
796 case 's':
797 conf_string(submenu);
798 break;
799 case 'L':
800 conf_load();
801 break;
802 case 'S':
803 conf_save();
804 break;
806 break;
807 case 2:
808 if (sym)
809 show_help(submenu);
810 else
811 show_helptext("README", _(mconf_readme));
812 break;
813 case 3:
814 if (type == 't') {
815 if (sym_set_tristate_value(sym, yes))
816 break;
817 if (sym_set_tristate_value(sym, mod))
818 show_textbox(NULL, setmod_text, 6, 74);
820 break;
821 case 4:
822 if (type == 't')
823 sym_set_tristate_value(sym, no);
824 break;
825 case 5:
826 if (type == 't')
827 sym_set_tristate_value(sym, mod);
828 break;
829 case 6:
830 if (type == 't')
831 sym_toggle_tristate_value(sym);
832 else if (type == 'm')
833 conf(submenu);
834 break;
835 case 7:
836 search_conf();
837 break;
842 static void show_textbox(const char *title, const char *text, int r, int c)
844 int fd;
846 fd = creat(".help.tmp", 0777);
847 write(fd, text, strlen(text));
848 close(fd);
849 show_file(".help.tmp", title, r, c);
850 unlink(".help.tmp");
853 static void show_helptext(const char *title, const char *text)
855 show_textbox(title, text, 0, 0);
858 static void show_help(struct menu *menu)
860 struct gstr help = str_new();
861 struct symbol *sym = menu->sym;
863 if (sym->help)
865 if (sym->name) {
866 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
867 str_append(&help, _(sym->help));
868 str_append(&help, "\n");
870 } else {
871 str_append(&help, nohelp_text);
873 get_symbol_str(&help, sym);
874 show_helptext(menu_get_prompt(menu), str_get(&help));
875 str_free(&help);
878 static void show_file(const char *filename, const char *title, int r, int c)
880 do {
881 cprint_init();
882 if (title) {
883 cprint("--title");
884 cprint("%s", title);
886 cprint("--textbox");
887 cprint("%s", filename);
888 cprint("%d", r ? r : rows);
889 cprint("%d", c ? c : cols);
890 } while (exec_conf() < 0);
893 static void conf_choice(struct menu *menu)
895 const char *prompt = menu_get_prompt(menu);
896 struct menu *child;
897 struct symbol *active;
898 int stat;
900 active = sym_get_choice_value(menu->sym);
901 while (1) {
902 cprint_init();
903 cprint("--title");
904 cprint("%s", prompt ? prompt : _("Main Menu"));
905 cprint("--radiolist");
906 cprint(_(radiolist_instructions));
907 cprint("15");
908 cprint("70");
909 cprint("6");
911 current_menu = menu;
912 for (child = menu->list; child; child = child->next) {
913 if (!menu_is_visible(child))
914 continue;
915 cprint("%p", child);
916 cprint("%s", menu_get_prompt(child));
917 if (child->sym == sym_get_choice_value(menu->sym))
918 cprint("ON");
919 else if (child->sym == active)
920 cprint("SELECTED");
921 else
922 cprint("OFF");
925 stat = exec_conf();
926 switch (stat) {
927 case 0:
928 if (sscanf(input_buf, "%p", &child) != 1)
929 break;
930 sym_set_tristate_value(child->sym, yes);
931 return;
932 case 1:
933 if (sscanf(input_buf, "%p", &child) == 1) {
934 show_help(child);
935 active = child->sym;
936 } else
937 show_help(menu);
938 break;
939 case 255:
940 return;
945 static void conf_string(struct menu *menu)
947 const char *prompt = menu_get_prompt(menu);
948 int stat;
950 while (1) {
951 cprint_init();
952 cprint("--title");
953 cprint("%s", prompt ? prompt : _("Main Menu"));
954 cprint("--inputbox");
955 switch (sym_get_type(menu->sym)) {
956 case S_INT:
957 cprint(_(inputbox_instructions_int));
958 break;
959 case S_HEX:
960 cprint(_(inputbox_instructions_hex));
961 break;
962 case S_STRING:
963 cprint(_(inputbox_instructions_string));
964 break;
965 default:
966 /* panic? */;
968 cprint("10");
969 cprint("75");
970 cprint("%s", sym_get_string_value(menu->sym));
971 stat = exec_conf();
972 switch (stat) {
973 case 0:
974 if (sym_set_string_value(menu->sym, input_buf))
975 return;
976 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
977 break;
978 case 1:
979 show_help(menu);
980 break;
981 case 255:
982 return;
987 static void conf_load(void)
989 int stat;
991 while (1) {
992 cprint_init();
993 cprint("--inputbox");
994 cprint(load_config_text);
995 cprint("11");
996 cprint("55");
997 cprint("%s", filename);
998 stat = exec_conf();
999 switch(stat) {
1000 case 0:
1001 if (!input_buf[0])
1002 return;
1003 if (!conf_read(input_buf))
1004 return;
1005 show_textbox(NULL, _("File does not exist!"), 5, 38);
1006 break;
1007 case 1:
1008 show_helptext(_("Load Alternate Configuration"), load_config_help);
1009 break;
1010 case 255:
1011 return;
1016 static void conf_save(void)
1018 int stat;
1020 while (1) {
1021 cprint_init();
1022 cprint("--inputbox");
1023 cprint(save_config_text);
1024 cprint("11");
1025 cprint("55");
1026 cprint("%s", filename);
1027 stat = exec_conf();
1028 switch(stat) {
1029 case 0:
1030 if (!input_buf[0])
1031 return;
1032 if (!conf_write(input_buf))
1033 return;
1034 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1035 break;
1036 case 1:
1037 show_helptext(_("Save Alternate Configuration"), save_config_help);
1038 break;
1039 case 255:
1040 return;
1045 static void conf_cleanup(void)
1047 tcsetattr(1, TCSAFLUSH, &ios_org);
1048 unlink(".help.tmp");
1049 unlink("lxdialog.scrltmp");
1052 int main(int ac, char **av)
1054 struct symbol *sym;
1055 char *mode;
1056 int stat;
1058 setlocale(LC_ALL, "");
1059 bindtextdomain(PACKAGE, LOCALEDIR);
1060 textdomain(PACKAGE);
1062 conf_parse(av[1]);
1063 conf_read(NULL);
1065 sym = sym_lookup("KERNELVERSION", 0);
1066 sym_calc_value(sym);
1067 sprintf(menu_backtitle, _("BusyBox %s Configuration"),
1068 sym_get_string_value(sym));
1070 mode = getenv("MENUCONFIG_MODE");
1071 if (mode) {
1072 if (!strcasecmp(mode, "single_menu"))
1073 single_menu_mode = 1;
1076 tcgetattr(1, &ios_org);
1077 atexit(conf_cleanup);
1078 init_wsize();
1079 conf(&rootmenu);
1081 do {
1082 cprint_init();
1083 cprint("--yesno");
1084 cprint(_("Do you wish to save your new configuration?"));
1085 cprint("5");
1086 cprint("60");
1087 stat = exec_conf();
1088 } while (stat < 0);
1090 if (stat == 0) {
1091 if (conf_write(NULL)) {
1092 fprintf(stderr, _("\n\n"
1093 "Error during writing of the configuration.\n"
1094 "Your configuration changes were NOT saved."
1095 "\n\n"));
1096 return 1;
1098 printf(_("\n\n"
1099 "*** End of configuration.\n"
1100 "*** Execute 'make' to build the project or try 'make help'."
1101 "\n\n"));
1102 } else {
1103 fprintf(stderr, _("\n\n"
1104 "Your configuration changes were NOT saved."
1105 "\n\n"));
1108 return 0;