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