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