blob: 810b018f19e09e439e1810e9ee4c49edb73f0f9a [file] [log] [blame]
Denis Vlasenko7d219aa2006-10-05 10:17:08 +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 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9 */
10
11#include <sys/ioctl.h>
12#include <sys/wait.h>
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <limits.h>
17#include <signal.h>
18#include <stdarg.h>
19#include <stdlib.h>
20#include <string.h>
21#include <termios.h>
22#include <unistd.h>
23#include <locale.h>
24
25#define LKC_DIRECT_LINK
26#include "lkc.h"
27
28static char menu_backtitle[128];
29static const char mconf_readme[] = N_(
30"Overview\n"
31"--------\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +000032"Some features may be built directly into busybox.\n"
33"Some may be made into standalone applets. Some features\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000034"may be completely removed altogether. There are also certain\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +000035"parameters which are not really features, but must be\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000036"entered in as decimal or hexadecimal numbers or possibly text.\n"
37"\n"
38"Menu items beginning with [*], <M> or [ ] represent features\n"
39"configured to be built in, modularized or removed respectively.\n"
40"Pointed brackets <> represent module capable features.\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, <M> to make it a module or\n"
44"<N> to removed it. You may also press the <Space Bar> to cycle\n"
45"through the available options (ie. Y->N->M->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"
Denis Vlasenkoeb98be02006-11-30 22:40:32 +0000118"between different busybox configurations.\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000119"\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"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000151"If you prefer to have all of the busybox options listed in a single\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000152"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[] = N_(
164 "Arrow keys navigate the menu. "
165 "<Enter> selects submenus --->. "
166 "Highlighted letters are hotkeys. "
167 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
168 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
169 "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
170radiolist_instructions[] = N_(
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[] = N_(
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[] = N_(
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[] = N_(
183 "Please enter a string value. "
184 "Use the <TAB> key to move from the input field to the buttons below it."),
185setmod_text[] = N_(
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[] = N_(
Denis Vlasenko3697a822007-01-06 10:31:45 +0000189 "There is no help available for this option.\n"),
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000190load_config_text[] = N_(
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[] = N_(
195 "\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000196 "For various reasons, one may wish to keep several different busybox\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000197 "configurations available on a single machine.\n"
198 "\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000199 "If you have saved a previous configuration in a file other than \n"
200 "busybox's default, entering the name of the file here will allow you\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000201 "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[] = N_(
206 "Enter a filename to which this configuration should be saved "
207 "as an alternate. Leave blank to abort."),
208save_config_help[] = N_(
209 "\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000210 "For various reasons, one may wish to keep different busybox\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000211 "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[] = N_(
220 "\n"
221 "Search for CONFIG_ symbols and display their relations.\n"
222 "Regular expressions are allowed.\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"
250 "\n"
251 "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");
258
259static char buf[4096], *bufptr = buf;
260static char input_buf[4096];
261static char filename[PATH_MAX+1] = ".config";
262static char *args[1024], **argptr = args;
263static int indent;
264static struct termios ios_org;
265static int rows = 0, cols = 0;
266static struct menu *current_menu;
267static int child_count;
268static int do_resize;
269static int single_menu_mode;
270
271static void conf(struct menu *menu);
272static void conf_choice(struct menu *menu);
273static void conf_string(struct menu *menu);
274static void conf_load(void);
275static void conf_save(void);
276static void show_textbox(const char *title, const char *text, int r, int c);
277static void show_helptext(const char *title, const char *text);
278static void show_help(struct menu *menu);
279static void show_file(const char *filename, const char *title, int r, int c);
280
281static void cprint_init(void);
282static int cprint1(const char *fmt, ...);
283static void cprint_done(void);
284static int cprint(const char *fmt, ...);
285
286static void init_wsize(void)
287{
288 struct winsize ws;
289 char *env;
290
291 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
292 rows = ws.ws_row;
293 cols = ws.ws_col;
294 }
295
296 if (!rows) {
297 env = getenv("LINES");
298 if (env)
299 rows = atoi(env);
300 if (!rows)
301 rows = 24;
302 }
303 if (!cols) {
304 env = getenv("COLUMNS");
305 if (env)
306 cols = atoi(env);
307 if (!cols)
308 cols = 80;
309 }
310
311 if (rows < 19 || cols < 80) {
312 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
313 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
314 exit(1);
315 }
316
317 rows -= 4;
318 cols -= 5;
319}
320
321static void cprint_init(void)
322{
323 bufptr = buf;
324 argptr = args;
325 memset(args, 0, sizeof(args));
326 indent = 0;
327 child_count = 0;
328 cprint("./scripts/kconfig/lxdialog/lxdialog");
329 cprint("--backtitle");
330 cprint(menu_backtitle);
331}
332
333static int cprint1(const char *fmt, ...)
334{
335 va_list ap;
336 int res;
337
338 if (!*argptr)
339 *argptr = bufptr;
340 va_start(ap, fmt);
341 res = vsprintf(bufptr, fmt, ap);
342 va_end(ap);
343 bufptr += res;
344
345 return res;
346}
347
348static void cprint_done(void)
349{
350 *bufptr++ = 0;
351 argptr++;
352}
353
354static int cprint(const char *fmt, ...)
355{
356 va_list ap;
357 int res;
358
359 *argptr++ = bufptr;
360 va_start(ap, fmt);
361 res = vsprintf(bufptr, fmt, ap);
362 va_end(ap);
363 bufptr += res;
364 *bufptr++ = 0;
365
366 return res;
367}
368
369static void get_prompt_str(struct gstr *r, struct property *prop)
370{
371 int i, j;
372 struct menu *submenu[8], *menu;
373
374 str_printf(r, "Prompt: %s\n", prop->text);
375 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
376 prop->menu->lineno);
377 if (!expr_is_yes(prop->visible.expr)) {
378 str_append(r, " Depends on: ");
379 expr_gstr_print(prop->visible.expr, r);
380 str_append(r, "\n");
381 }
382 menu = prop->menu->parent;
383 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
384 submenu[i++] = menu;
385 if (i > 0) {
386 str_printf(r, " Location:\n");
387 for (j = 4; --i >= 0; j += 2) {
388 menu = submenu[i];
389 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
390 if (menu->sym) {
391 str_printf(r, " (%s [=%s])", menu->sym->name ?
392 menu->sym->name : "<choice>",
393 sym_get_string_value(menu->sym));
394 }
395 str_append(r, "\n");
396 }
397 }
398}
399
400static void get_symbol_str(struct gstr *r, struct symbol *sym)
401{
402 bool hit;
403 struct property *prop;
404
405 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
406 sym_get_string_value(sym));
407 for_all_prompts(sym, prop)
408 get_prompt_str(r, prop);
409 hit = false;
410 for_all_properties(sym, prop, P_SELECT) {
411 if (!hit) {
412 str_append(r, " Selects: ");
413 hit = true;
414 } else
415 str_printf(r, " && ");
416 expr_gstr_print(prop->expr, r);
417 }
418 if (hit)
419 str_append(r, "\n");
420 if (sym->rev_dep.expr) {
421 str_append(r, " Selected by: ");
422 expr_gstr_print(sym->rev_dep.expr, r);
423 str_append(r, "\n");
424 }
425 str_append(r, "\n\n");
426}
427
428static struct gstr get_relations_str(struct symbol **sym_arr)
429{
430 struct symbol *sym;
431 struct gstr res = str_new();
432 int i;
433
434 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
435 get_symbol_str(&res, sym);
436 if (!i)
437 str_append(&res, "No matches found.\n");
438 return res;
439}
440
441pid_t pid;
442
443static void winch_handler(int sig)
444{
445 if (!do_resize) {
446 kill(pid, SIGINT);
447 do_resize = 1;
448 }
449}
450
451static int exec_conf(void)
452{
453 int pipefd[2], stat, size;
454 struct sigaction sa;
455 sigset_t sset, osset;
456
457 sigemptyset(&sset);
458 sigaddset(&sset, SIGINT);
459 sigprocmask(SIG_BLOCK, &sset, &osset);
460
461 signal(SIGINT, SIG_DFL);
462
463 sa.sa_handler = winch_handler;
464 sigemptyset(&sa.sa_mask);
465 sa.sa_flags = SA_RESTART;
466 sigaction(SIGWINCH, &sa, NULL);
467
468 *argptr++ = NULL;
469
470 pipe(pipefd);
471 pid = fork();
472 if (pid == 0) {
473 sigprocmask(SIG_SETMASK, &osset, NULL);
474 dup2(pipefd[1], 2);
475 close(pipefd[0]);
476 close(pipefd[1]);
477 execv(args[0], args);
478 _exit(EXIT_FAILURE);
479 }
480
481 close(pipefd[1]);
482 bufptr = input_buf;
483 while (1) {
484 size = input_buf + sizeof(input_buf) - bufptr;
485 size = read(pipefd[0], bufptr, size);
486 if (size <= 0) {
487 if (size < 0) {
488 if (errno == EINTR || errno == EAGAIN)
489 continue;
490 perror("read");
491 }
492 break;
493 }
494 bufptr += size;
495 }
496 *bufptr++ = 0;
497 close(pipefd[0]);
498 waitpid(pid, &stat, 0);
499
500 if (do_resize) {
501 init_wsize();
502 do_resize = 0;
503 sigprocmask(SIG_SETMASK, &osset, NULL);
504 return -1;
505 }
506 if (WIFSIGNALED(stat)) {
507 printf("\finterrupted(%d)\n", WTERMSIG(stat));
508 exit(1);
509 }
510#if 0
511 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
512 sleep(1);
513#endif
514 sigpending(&sset);
515 if (sigismember(&sset, SIGINT)) {
516 printf("\finterrupted\n");
517 exit(1);
518 }
519 sigprocmask(SIG_SETMASK, &osset, NULL);
520
521 return WEXITSTATUS(stat);
522}
523
524static void search_conf(void)
525{
526 struct symbol **sym_arr;
527 int stat;
528 struct gstr res;
529
530again:
531 cprint_init();
532 cprint("--title");
533 cprint(_("Search Configuration Parameter"));
534 cprint("--inputbox");
535 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
536 cprint("10");
537 cprint("75");
538 cprint("");
539 stat = exec_conf();
540 if (stat < 0)
541 goto again;
542 switch (stat) {
543 case 0:
544 break;
545 case 1:
546 show_helptext(_("Search Configuration"), search_help);
547 goto again;
548 default:
549 return;
550 }
551
552 sym_arr = sym_re_search(input_buf);
553 res = get_relations_str(sym_arr);
554 free(sym_arr);
555 show_textbox(_("Search Results"), str_get(&res), 0, 0);
556 str_free(&res);
557}
558
559static void build_conf(struct menu *menu)
560{
561 struct symbol *sym;
562 struct property *prop;
563 struct menu *child;
564 int type, tmp, doint = 2;
565 tristate val;
566 char ch;
567
568 if (!menu_is_visible(menu))
569 return;
570
571 sym = menu->sym;
572 prop = menu->prompt;
573 if (!sym) {
574 if (prop && menu != current_menu) {
575 const char *prompt = menu_get_prompt(menu);
576 switch (prop->type) {
577 case P_MENU:
578 child_count++;
579 cprint("m%p", menu);
580
581 if (single_menu_mode) {
582 cprint1("%s%*c%s",
583 menu->data ? "-->" : "++>",
584 indent + 1, ' ', prompt);
585 } else
586 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
587
588 cprint_done();
589 if (single_menu_mode && menu->data)
590 goto conf_childs;
591 return;
592 default:
593 if (prompt) {
594 child_count++;
595 cprint(":%p", menu);
596 cprint("---%*c%s", indent + 1, ' ', prompt);
597 }
598 }
599 } else
600 doint = 0;
601 goto conf_childs;
602 }
603
604 type = sym_get_type(sym);
605 if (sym_is_choice(sym)) {
606 struct symbol *def_sym = sym_get_choice_value(sym);
607 struct menu *def_menu = NULL;
608
609 child_count++;
610 for (child = menu->list; child; child = child->next) {
611 if (menu_is_visible(child) && child->sym == def_sym)
612 def_menu = child;
613 }
614
615 val = sym_get_tristate_value(sym);
616 if (sym_is_changable(sym)) {
617 cprint("t%p", menu);
618 switch (type) {
619 case S_BOOLEAN:
620 cprint1("[%c]", val == no ? ' ' : '*');
621 break;
622 case S_TRISTATE:
623 switch (val) {
624 case yes: ch = '*'; break;
625 case mod: ch = 'M'; break;
626 default: ch = ' '; break;
627 }
628 cprint1("<%c>", ch);
629 break;
630 }
631 } else {
632 cprint("%c%p", def_menu ? 't' : ':', menu);
633 cprint1(" ");
634 }
635
636 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
637 if (val == yes) {
638 if (def_menu) {
639 cprint1(" (%s)", menu_get_prompt(def_menu));
640 cprint1(" --->");
641 cprint_done();
642 if (def_menu->list) {
643 indent += 2;
644 build_conf(def_menu);
645 indent -= 2;
646 }
647 } else
648 cprint_done();
649 return;
650 }
651 cprint_done();
652 } else {
653 if (menu == current_menu) {
654 cprint(":%p", menu);
655 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
656 goto conf_childs;
657 }
658 child_count++;
659 val = sym_get_tristate_value(sym);
660 if (sym_is_choice_value(sym) && val == yes) {
661 cprint(":%p", menu);
662 cprint1(" ");
663 } else {
664 switch (type) {
665 case S_BOOLEAN:
666 cprint("t%p", menu);
667 if (sym_is_changable(sym))
668 cprint1("[%c]", val == no ? ' ' : '*');
669 else
670 cprint1("---");
671 break;
672 case S_TRISTATE:
673 cprint("t%p", menu);
674 switch (val) {
675 case yes: ch = '*'; break;
676 case mod: ch = 'M'; break;
677 default: ch = ' '; break;
678 }
679 if (sym_is_changable(sym))
680 cprint1("<%c>", ch);
681 else
682 cprint1("---");
683 break;
684 default:
685 cprint("s%p", menu);
686 tmp = cprint1("(%s)", sym_get_string_value(sym));
687 tmp = indent - tmp + 4;
688 if (tmp < 0)
689 tmp = 0;
690 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
691 (sym_has_value(sym) || !sym_is_changable(sym)) ?
692 "" : " (NEW)");
693 cprint_done();
694 goto conf_childs;
695 }
696 }
697 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
698 (sym_has_value(sym) || !sym_is_changable(sym)) ?
699 "" : " (NEW)");
700 if (menu->prompt->type == P_MENU) {
701 cprint1(" --->");
702 cprint_done();
703 return;
704 }
705 cprint_done();
706 }
707
708conf_childs:
709 indent += doint;
710 for (child = menu->list; child; child = child->next)
711 build_conf(child);
712 indent -= doint;
713}
714
715static void conf(struct menu *menu)
716{
717 struct menu *submenu;
718 const char *prompt = menu_get_prompt(menu);
719 struct symbol *sym;
720 char active_entry[40];
721 int stat, type, i;
722
723 unlink("lxdialog.scrltmp");
724 active_entry[0] = 0;
725 while (1) {
726 cprint_init();
727 cprint("--title");
728 cprint("%s", prompt ? prompt : _("Main Menu"));
729 cprint("--menu");
730 cprint(_(menu_instructions));
731 cprint("%d", rows);
732 cprint("%d", cols);
733 cprint("%d", rows - 10);
734 cprint("%s", active_entry);
735 current_menu = menu;
736 build_conf(menu);
737 if (!child_count)
738 break;
739 if (menu == &rootmenu) {
740 cprint(":");
741 cprint("--- ");
742 cprint("L");
743 cprint(_(" Load an Alternate Configuration File"));
744 cprint("S");
745 cprint(_(" Save Configuration to an Alternate File"));
746 }
747 stat = exec_conf();
748 if (stat < 0)
749 continue;
750
751 if (stat == 1 || stat == 255)
752 break;
753
754 type = input_buf[0];
755 if (!type)
756 continue;
757
758 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
759 ;
760 if (i >= sizeof(active_entry))
761 i = sizeof(active_entry) - 1;
762 input_buf[i] = 0;
763 strcpy(active_entry, input_buf);
764
765 sym = NULL;
766 submenu = NULL;
767 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
768 sym = submenu->sym;
769
770 switch (stat) {
771 case 0:
772 switch (type) {
773 case 'm':
774 if (single_menu_mode)
775 submenu->data = (void *) (long) !submenu->data;
776 else
777 conf(submenu);
778 break;
779 case 't':
780 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
781 conf_choice(submenu);
782 else if (submenu->prompt->type == P_MENU)
783 conf(submenu);
784 break;
785 case 's':
786 conf_string(submenu);
787 break;
788 case 'L':
789 conf_load();
790 break;
791 case 'S':
792 conf_save();
793 break;
794 }
795 break;
796 case 2:
797 if (sym)
798 show_help(submenu);
799 else
800 show_helptext("README", _(mconf_readme));
801 break;
802 case 3:
803 if (type == 't') {
804 if (sym_set_tristate_value(sym, yes))
805 break;
806 if (sym_set_tristate_value(sym, mod))
807 show_textbox(NULL, setmod_text, 6, 74);
808 }
809 break;
810 case 4:
811 if (type == 't')
812 sym_set_tristate_value(sym, no);
813 break;
814 case 5:
815 if (type == 't')
816 sym_set_tristate_value(sym, mod);
817 break;
818 case 6:
819 if (type == 't')
820 sym_toggle_tristate_value(sym);
821 else if (type == 'm')
822 conf(submenu);
823 break;
824 case 7:
825 search_conf();
826 break;
827 }
828 }
829}
830
831static void show_textbox(const char *title, const char *text, int r, int c)
832{
833 int fd;
834
835 fd = creat(".help.tmp", 0777);
836 write(fd, text, strlen(text));
837 close(fd);
838 show_file(".help.tmp", title, r, c);
839 unlink(".help.tmp");
840}
841
842static void show_helptext(const char *title, const char *text)
843{
844 show_textbox(title, text, 0, 0);
845}
846
847static void show_help(struct menu *menu)
848{
849 struct gstr help = str_new();
850 struct symbol *sym = menu->sym;
851
852 if (sym->help)
853 {
854 if (sym->name) {
855 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
856 str_append(&help, _(sym->help));
857 str_append(&help, "\n");
858 }
859 } else {
860 str_append(&help, nohelp_text);
861 }
862 get_symbol_str(&help, sym);
863 show_helptext(menu_get_prompt(menu), str_get(&help));
864 str_free(&help);
865}
866
867static void show_file(const char *filename, const char *title, int r, int c)
868{
869 do {
870 cprint_init();
871 if (title) {
872 cprint("--title");
873 cprint("%s", title);
874 }
875 cprint("--textbox");
876 cprint("%s", filename);
877 cprint("%d", r ? r : rows);
878 cprint("%d", c ? c : cols);
879 } while (exec_conf() < 0);
880}
881
882static void conf_choice(struct menu *menu)
883{
884 const char *prompt = menu_get_prompt(menu);
885 struct menu *child;
886 struct symbol *active;
887 int stat;
888
889 active = sym_get_choice_value(menu->sym);
890 while (1) {
891 cprint_init();
892 cprint("--title");
893 cprint("%s", prompt ? prompt : _("Main Menu"));
894 cprint("--radiolist");
895 cprint(_(radiolist_instructions));
896 cprint("15");
897 cprint("70");
898 cprint("6");
899
900 current_menu = menu;
901 for (child = menu->list; child; child = child->next) {
902 if (!menu_is_visible(child))
903 continue;
904 cprint("%p", child);
905 cprint("%s", menu_get_prompt(child));
906 if (child->sym == sym_get_choice_value(menu->sym))
907 cprint("ON");
908 else if (child->sym == active)
909 cprint("SELECTED");
910 else
911 cprint("OFF");
912 }
913
914 stat = exec_conf();
915 switch (stat) {
916 case 0:
917 if (sscanf(input_buf, "%p", &child) != 1)
918 break;
919 sym_set_tristate_value(child->sym, yes);
920 return;
921 case 1:
922 if (sscanf(input_buf, "%p", &child) == 1) {
923 show_help(child);
924 active = child->sym;
925 } else
926 show_help(menu);
927 break;
928 case 255:
929 return;
930 }
931 }
932}
933
934static void conf_string(struct menu *menu)
935{
936 const char *prompt = menu_get_prompt(menu);
937 int stat;
938
939 while (1) {
940 cprint_init();
941 cprint("--title");
942 cprint("%s", prompt ? prompt : _("Main Menu"));
943 cprint("--inputbox");
944 switch (sym_get_type(menu->sym)) {
945 case S_INT:
946 cprint(_(inputbox_instructions_int));
947 break;
948 case S_HEX:
949 cprint(_(inputbox_instructions_hex));
950 break;
951 case S_STRING:
952 cprint(_(inputbox_instructions_string));
953 break;
954 default:
955 /* panic? */;
956 }
957 cprint("10");
958 cprint("75");
959 cprint("%s", sym_get_string_value(menu->sym));
960 stat = exec_conf();
961 switch (stat) {
962 case 0:
963 if (sym_set_string_value(menu->sym, input_buf))
964 return;
965 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
966 break;
967 case 1:
968 show_help(menu);
969 break;
970 case 255:
971 return;
972 }
973 }
974}
975
976static void conf_load(void)
977{
978 int stat;
979
980 while (1) {
981 cprint_init();
982 cprint("--inputbox");
983 cprint(load_config_text);
984 cprint("11");
985 cprint("55");
986 cprint("%s", filename);
987 stat = exec_conf();
988 switch(stat) {
989 case 0:
990 if (!input_buf[0])
991 return;
992 if (!conf_read(input_buf))
993 return;
994 show_textbox(NULL, _("File does not exist!"), 5, 38);
995 break;
996 case 1:
997 show_helptext(_("Load Alternate Configuration"), load_config_help);
998 break;
999 case 255:
1000 return;
1001 }
1002 }
1003}
1004
1005static void conf_save(void)
1006{
1007 int stat;
1008
1009 while (1) {
1010 cprint_init();
1011 cprint("--inputbox");
1012 cprint(save_config_text);
1013 cprint("11");
1014 cprint("55");
1015 cprint("%s", filename);
1016 stat = exec_conf();
1017 switch(stat) {
1018 case 0:
1019 if (!input_buf[0])
1020 return;
1021 if (!conf_write(input_buf))
1022 return;
1023 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1024 break;
1025 case 1:
1026 show_helptext(_("Save Alternate Configuration"), save_config_help);
1027 break;
1028 case 255:
1029 return;
1030 }
1031 }
1032}
1033
1034static void conf_cleanup(void)
1035{
1036 tcsetattr(1, TCSAFLUSH, &ios_org);
1037 unlink(".help.tmp");
1038 unlink("lxdialog.scrltmp");
1039}
1040
1041int main(int ac, char **av)
1042{
1043 struct symbol *sym;
1044 char *mode;
1045 int stat;
1046
1047 setlocale(LC_ALL, "");
1048 bindtextdomain(PACKAGE, LOCALEDIR);
1049 textdomain(PACKAGE);
1050
1051 conf_parse(av[1]);
1052 conf_read(NULL);
1053
1054 sym = sym_lookup("KERNELVERSION", 0);
1055 sym_calc_value(sym);
Denis Vlasenko3697a822007-01-06 10:31:45 +00001056 sprintf(menu_backtitle, _("BusyBox %s Configuration"),
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001057 sym_get_string_value(sym));
1058
1059 mode = getenv("MENUCONFIG_MODE");
1060 if (mode) {
1061 if (!strcasecmp(mode, "single_menu"))
1062 single_menu_mode = 1;
1063 }
1064
1065 tcgetattr(1, &ios_org);
1066 atexit(conf_cleanup);
1067 init_wsize();
1068 conf(&rootmenu);
1069
1070 do {
1071 cprint_init();
1072 cprint("--yesno");
Denis Vlasenkoeb98be02006-11-30 22:40:32 +00001073 cprint(_("Do you wish to save your new busybox configuration?"));
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001074 cprint("5");
1075 cprint("60");
1076 stat = exec_conf();
1077 } while (stat < 0);
1078
1079 if (stat == 0) {
1080 if (conf_write(NULL)) {
1081 fprintf(stderr, _("\n\n"
Denis Vlasenkoeb98be02006-11-30 22:40:32 +00001082 "Error during writing of the busybox configuration.\n"
1083 "Your busybox configuration changes were NOT saved."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001084 "\n\n"));
1085 return 1;
1086 }
1087 printf(_("\n\n"
Denis Vlasenkoeb98be02006-11-30 22:40:32 +00001088 "*** End of busybox configuration.\n"
Denis Vlasenko3697a822007-01-06 10:31:45 +00001089 "*** Execute 'make' to build busybox or try 'make help'."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001090 "\n\n"));
1091 } else {
1092 fprintf(stderr, _("\n\n"
Denis Vlasenkoeb98be02006-11-30 22:40:32 +00001093 "Your busybox configuration changes were NOT saved."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001094 "\n\n"));
1095 }
1096
1097 return 0;
1098}