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