blob: 006d03708855ecfb181a6c68e363d9053c211b49 [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
Denys Vlasenko225cc132012-09-27 15:26:40 +0200448#ifdef SIGWINCH
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000449static void winch_handler(int sig)
450{
451 if (!do_resize) {
452 kill(pid, SIGINT);
453 do_resize = 1;
454 }
455}
Denys Vlasenko225cc132012-09-27 15:26:40 +0200456#endif
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000457
458static int exec_conf(void)
459{
460 int pipefd[2], stat, size;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000461 sigset_t sset, osset;
462
463 sigemptyset(&sset);
464 sigaddset(&sset, SIGINT);
465 sigprocmask(SIG_BLOCK, &sset, &osset);
466
467 signal(SIGINT, SIG_DFL);
468
Denys Vlasenko225cc132012-09-27 15:26:40 +0200469#ifdef SIGWINCH
470 {
471 struct sigaction sa;
472 sa.sa_handler = winch_handler;
473 sigemptyset(&sa.sa_mask);
474 sa.sa_flags = SA_RESTART;
475 sigaction(SIGWINCH, &sa, NULL);
476 }
477#endif
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000478
479 *argptr++ = NULL;
480
481 pipe(pipefd);
482 pid = fork();
483 if (pid == 0) {
484 sigprocmask(SIG_SETMASK, &osset, NULL);
485 dup2(pipefd[1], 2);
486 close(pipefd[0]);
487 close(pipefd[1]);
488 execv(args[0], args);
489 _exit(EXIT_FAILURE);
490 }
491
492 close(pipefd[1]);
493 bufptr = input_buf;
494 while (1) {
495 size = input_buf + sizeof(input_buf) - bufptr;
496 size = read(pipefd[0], bufptr, size);
497 if (size <= 0) {
498 if (size < 0) {
499 if (errno == EINTR || errno == EAGAIN)
500 continue;
501 perror("read");
502 }
503 break;
504 }
505 bufptr += size;
506 }
507 *bufptr++ = 0;
508 close(pipefd[0]);
509 waitpid(pid, &stat, 0);
510
511 if (do_resize) {
512 init_wsize();
513 do_resize = 0;
514 sigprocmask(SIG_SETMASK, &osset, NULL);
515 return -1;
516 }
517 if (WIFSIGNALED(stat)) {
518 printf("\finterrupted(%d)\n", WTERMSIG(stat));
519 exit(1);
520 }
521#if 0
522 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
523 sleep(1);
524#endif
525 sigpending(&sset);
526 if (sigismember(&sset, SIGINT)) {
527 printf("\finterrupted\n");
528 exit(1);
529 }
530 sigprocmask(SIG_SETMASK, &osset, NULL);
531
532 return WEXITSTATUS(stat);
533}
534
535static void search_conf(void)
536{
537 struct symbol **sym_arr;
538 int stat;
539 struct gstr res;
540
541again:
542 cprint_init();
543 cprint("--title");
544 cprint(_("Search Configuration Parameter"));
545 cprint("--inputbox");
546 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
547 cprint("10");
548 cprint("75");
549 cprint("");
550 stat = exec_conf();
551 if (stat < 0)
552 goto again;
553 switch (stat) {
554 case 0:
555 break;
556 case 1:
557 show_helptext(_("Search Configuration"), search_help);
558 goto again;
559 default:
560 return;
561 }
562
563 sym_arr = sym_re_search(input_buf);
564 res = get_relations_str(sym_arr);
565 free(sym_arr);
566 show_textbox(_("Search Results"), str_get(&res), 0, 0);
567 str_free(&res);
568}
569
570static void build_conf(struct menu *menu)
571{
572 struct symbol *sym;
573 struct property *prop;
574 struct menu *child;
575 int type, tmp, doint = 2;
576 tristate val;
577 char ch;
578
579 if (!menu_is_visible(menu))
580 return;
581
582 sym = menu->sym;
583 prop = menu->prompt;
584 if (!sym) {
585 if (prop && menu != current_menu) {
586 const char *prompt = menu_get_prompt(menu);
587 switch (prop->type) {
588 case P_MENU:
589 child_count++;
590 cprint("m%p", menu);
591
592 if (single_menu_mode) {
593 cprint1("%s%*c%s",
594 menu->data ? "-->" : "++>",
595 indent + 1, ' ', prompt);
596 } else
597 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
598
599 cprint_done();
600 if (single_menu_mode && menu->data)
601 goto conf_childs;
602 return;
603 default:
604 if (prompt) {
605 child_count++;
606 cprint(":%p", menu);
607 cprint("---%*c%s", indent + 1, ' ', prompt);
608 }
609 }
610 } else
611 doint = 0;
612 goto conf_childs;
613 }
614
615 type = sym_get_type(sym);
616 if (sym_is_choice(sym)) {
617 struct symbol *def_sym = sym_get_choice_value(sym);
618 struct menu *def_menu = NULL;
619
620 child_count++;
621 for (child = menu->list; child; child = child->next) {
622 if (menu_is_visible(child) && child->sym == def_sym)
623 def_menu = child;
624 }
625
626 val = sym_get_tristate_value(sym);
627 if (sym_is_changable(sym)) {
628 cprint("t%p", menu);
629 switch (type) {
630 case S_BOOLEAN:
631 cprint1("[%c]", val == no ? ' ' : '*');
632 break;
633 case S_TRISTATE:
634 switch (val) {
635 case yes: ch = '*'; break;
636 case mod: ch = 'M'; break;
637 default: ch = ' '; break;
638 }
639 cprint1("<%c>", ch);
640 break;
641 }
642 } else {
643 cprint("%c%p", def_menu ? 't' : ':', menu);
644 cprint1(" ");
645 }
646
647 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
648 if (val == yes) {
649 if (def_menu) {
650 cprint1(" (%s)", menu_get_prompt(def_menu));
651 cprint1(" --->");
652 cprint_done();
653 if (def_menu->list) {
654 indent += 2;
655 build_conf(def_menu);
656 indent -= 2;
657 }
658 } else
659 cprint_done();
660 return;
661 }
662 cprint_done();
663 } else {
664 if (menu == current_menu) {
665 cprint(":%p", menu);
666 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
667 goto conf_childs;
668 }
669 child_count++;
670 val = sym_get_tristate_value(sym);
671 if (sym_is_choice_value(sym) && val == yes) {
672 cprint(":%p", menu);
673 cprint1(" ");
674 } else {
675 switch (type) {
676 case S_BOOLEAN:
677 cprint("t%p", menu);
678 if (sym_is_changable(sym))
679 cprint1("[%c]", val == no ? ' ' : '*');
680 else
681 cprint1("---");
682 break;
683 case S_TRISTATE:
684 cprint("t%p", menu);
685 switch (val) {
686 case yes: ch = '*'; break;
687 case mod: ch = 'M'; break;
688 default: ch = ' '; break;
689 }
690 if (sym_is_changable(sym))
691 cprint1("<%c>", ch);
692 else
693 cprint1("---");
694 break;
695 default:
696 cprint("s%p", menu);
697 tmp = cprint1("(%s)", sym_get_string_value(sym));
698 tmp = indent - tmp + 4;
699 if (tmp < 0)
700 tmp = 0;
701 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
702 (sym_has_value(sym) || !sym_is_changable(sym)) ?
703 "" : " (NEW)");
704 cprint_done();
705 goto conf_childs;
706 }
707 }
708 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
709 (sym_has_value(sym) || !sym_is_changable(sym)) ?
710 "" : " (NEW)");
711 if (menu->prompt->type == P_MENU) {
712 cprint1(" --->");
713 cprint_done();
714 return;
715 }
716 cprint_done();
717 }
718
719conf_childs:
720 indent += doint;
721 for (child = menu->list; child; child = child->next)
722 build_conf(child);
723 indent -= doint;
724}
725
726static void conf(struct menu *menu)
727{
728 struct menu *submenu;
729 const char *prompt = menu_get_prompt(menu);
730 struct symbol *sym;
731 char active_entry[40];
732 int stat, type, i;
733
734 unlink("lxdialog.scrltmp");
735 active_entry[0] = 0;
736 while (1) {
737 cprint_init();
738 cprint("--title");
739 cprint("%s", prompt ? prompt : _("Main Menu"));
740 cprint("--menu");
741 cprint(_(menu_instructions));
742 cprint("%d", rows);
743 cprint("%d", cols);
744 cprint("%d", rows - 10);
745 cprint("%s", active_entry);
746 current_menu = menu;
747 build_conf(menu);
748 if (!child_count)
749 break;
750 if (menu == &rootmenu) {
751 cprint(":");
752 cprint("--- ");
753 cprint("L");
754 cprint(_(" Load an Alternate Configuration File"));
755 cprint("S");
756 cprint(_(" Save Configuration to an Alternate File"));
757 }
758 stat = exec_conf();
759 if (stat < 0)
760 continue;
761
762 if (stat == 1 || stat == 255)
763 break;
764
765 type = input_buf[0];
766 if (!type)
767 continue;
768
769 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
770 ;
771 if (i >= sizeof(active_entry))
772 i = sizeof(active_entry) - 1;
773 input_buf[i] = 0;
774 strcpy(active_entry, input_buf);
775
776 sym = NULL;
777 submenu = NULL;
778 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
779 sym = submenu->sym;
780
781 switch (stat) {
782 case 0:
783 switch (type) {
784 case 'm':
785 if (single_menu_mode)
786 submenu->data = (void *) (long) !submenu->data;
787 else
788 conf(submenu);
789 break;
790 case 't':
791 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
792 conf_choice(submenu);
793 else if (submenu->prompt->type == P_MENU)
794 conf(submenu);
795 break;
796 case 's':
797 conf_string(submenu);
798 break;
799 case 'L':
800 conf_load();
801 break;
802 case 'S':
803 conf_save();
804 break;
805 }
806 break;
807 case 2:
808 if (sym)
809 show_help(submenu);
810 else
811 show_helptext("README", _(mconf_readme));
812 break;
813 case 3:
814 if (type == 't') {
815 if (sym_set_tristate_value(sym, yes))
816 break;
817 if (sym_set_tristate_value(sym, mod))
818 show_textbox(NULL, setmod_text, 6, 74);
819 }
820 break;
821 case 4:
822 if (type == 't')
823 sym_set_tristate_value(sym, no);
824 break;
825 case 5:
826 if (type == 't')
827 sym_set_tristate_value(sym, mod);
828 break;
829 case 6:
830 if (type == 't')
831 sym_toggle_tristate_value(sym);
832 else if (type == 'm')
833 conf(submenu);
834 break;
835 case 7:
836 search_conf();
837 break;
838 }
839 }
840}
841
842static void show_textbox(const char *title, const char *text, int r, int c)
843{
844 int fd;
845
846 fd = creat(".help.tmp", 0777);
847 write(fd, text, strlen(text));
848 close(fd);
849 show_file(".help.tmp", title, r, c);
850 unlink(".help.tmp");
851}
852
853static void show_helptext(const char *title, const char *text)
854{
855 show_textbox(title, text, 0, 0);
856}
857
858static void show_help(struct menu *menu)
859{
860 struct gstr help = str_new();
861 struct symbol *sym = menu->sym;
862
863 if (sym->help)
864 {
865 if (sym->name) {
866 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
867 str_append(&help, _(sym->help));
868 str_append(&help, "\n");
869 }
870 } else {
871 str_append(&help, nohelp_text);
872 }
873 get_symbol_str(&help, sym);
874 show_helptext(menu_get_prompt(menu), str_get(&help));
875 str_free(&help);
876}
877
878static void show_file(const char *filename, const char *title, int r, int c)
879{
880 do {
881 cprint_init();
882 if (title) {
883 cprint("--title");
884 cprint("%s", title);
885 }
886 cprint("--textbox");
887 cprint("%s", filename);
888 cprint("%d", r ? r : rows);
889 cprint("%d", c ? c : cols);
890 } while (exec_conf() < 0);
891}
892
893static void conf_choice(struct menu *menu)
894{
895 const char *prompt = menu_get_prompt(menu);
896 struct menu *child;
897 struct symbol *active;
898 int stat;
899
900 active = sym_get_choice_value(menu->sym);
901 while (1) {
902 cprint_init();
903 cprint("--title");
904 cprint("%s", prompt ? prompt : _("Main Menu"));
905 cprint("--radiolist");
906 cprint(_(radiolist_instructions));
907 cprint("15");
908 cprint("70");
909 cprint("6");
910
911 current_menu = menu;
912 for (child = menu->list; child; child = child->next) {
913 if (!menu_is_visible(child))
914 continue;
915 cprint("%p", child);
916 cprint("%s", menu_get_prompt(child));
917 if (child->sym == sym_get_choice_value(menu->sym))
918 cprint("ON");
919 else if (child->sym == active)
920 cprint("SELECTED");
921 else
922 cprint("OFF");
923 }
924
925 stat = exec_conf();
926 switch (stat) {
927 case 0:
928 if (sscanf(input_buf, "%p", &child) != 1)
929 break;
930 sym_set_tristate_value(child->sym, yes);
931 return;
932 case 1:
933 if (sscanf(input_buf, "%p", &child) == 1) {
934 show_help(child);
935 active = child->sym;
936 } else
937 show_help(menu);
938 break;
939 case 255:
940 return;
941 }
942 }
943}
944
945static void conf_string(struct menu *menu)
946{
947 const char *prompt = menu_get_prompt(menu);
948 int stat;
949
950 while (1) {
951 cprint_init();
952 cprint("--title");
953 cprint("%s", prompt ? prompt : _("Main Menu"));
954 cprint("--inputbox");
955 switch (sym_get_type(menu->sym)) {
956 case S_INT:
957 cprint(_(inputbox_instructions_int));
958 break;
959 case S_HEX:
960 cprint(_(inputbox_instructions_hex));
961 break;
962 case S_STRING:
963 cprint(_(inputbox_instructions_string));
964 break;
965 default:
966 /* panic? */;
967 }
968 cprint("10");
969 cprint("75");
970 cprint("%s", sym_get_string_value(menu->sym));
971 stat = exec_conf();
972 switch (stat) {
973 case 0:
974 if (sym_set_string_value(menu->sym, input_buf))
975 return;
976 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
977 break;
978 case 1:
979 show_help(menu);
980 break;
981 case 255:
982 return;
983 }
984 }
985}
986
987static void conf_load(void)
988{
989 int stat;
990
991 while (1) {
992 cprint_init();
993 cprint("--inputbox");
994 cprint(load_config_text);
995 cprint("11");
996 cprint("55");
997 cprint("%s", filename);
998 stat = exec_conf();
999 switch(stat) {
1000 case 0:
1001 if (!input_buf[0])
1002 return;
1003 if (!conf_read(input_buf))
1004 return;
1005 show_textbox(NULL, _("File does not exist!"), 5, 38);
1006 break;
1007 case 1:
1008 show_helptext(_("Load Alternate Configuration"), load_config_help);
1009 break;
1010 case 255:
1011 return;
1012 }
1013 }
1014}
1015
1016static void conf_save(void)
1017{
1018 int stat;
1019
1020 while (1) {
1021 cprint_init();
1022 cprint("--inputbox");
1023 cprint(save_config_text);
1024 cprint("11");
1025 cprint("55");
1026 cprint("%s", filename);
1027 stat = exec_conf();
1028 switch(stat) {
1029 case 0:
1030 if (!input_buf[0])
1031 return;
1032 if (!conf_write(input_buf))
1033 return;
1034 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1035 break;
1036 case 1:
1037 show_helptext(_("Save Alternate Configuration"), save_config_help);
1038 break;
1039 case 255:
1040 return;
1041 }
1042 }
1043}
1044
1045static void conf_cleanup(void)
1046{
1047 tcsetattr(1, TCSAFLUSH, &ios_org);
1048 unlink(".help.tmp");
1049 unlink("lxdialog.scrltmp");
1050}
1051
1052int main(int ac, char **av)
1053{
1054 struct symbol *sym;
1055 char *mode;
1056 int stat;
1057
1058 setlocale(LC_ALL, "");
1059 bindtextdomain(PACKAGE, LOCALEDIR);
1060 textdomain(PACKAGE);
1061
1062 conf_parse(av[1]);
1063 conf_read(NULL);
1064
1065 sym = sym_lookup("KERNELVERSION", 0);
1066 sym_calc_value(sym);
Denis Vlasenko3697a822007-01-06 10:31:45 +00001067 sprintf(menu_backtitle, _("BusyBox %s Configuration"),
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001068 sym_get_string_value(sym));
1069
1070 mode = getenv("MENUCONFIG_MODE");
1071 if (mode) {
1072 if (!strcasecmp(mode, "single_menu"))
1073 single_menu_mode = 1;
1074 }
1075
1076 tcgetattr(1, &ios_org);
1077 atexit(conf_cleanup);
1078 init_wsize();
1079 conf(&rootmenu);
1080
1081 do {
1082 cprint_init();
1083 cprint("--yesno");
Denis Vlasenko417e2402008-05-28 11:59:32 +00001084 cprint(_("Do you wish to save your new configuration?"));
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001085 cprint("5");
1086 cprint("60");
1087 stat = exec_conf();
1088 } while (stat < 0);
1089
1090 if (stat == 0) {
1091 if (conf_write(NULL)) {
1092 fprintf(stderr, _("\n\n"
Denis Vlasenko417e2402008-05-28 11:59:32 +00001093 "Error during writing of the configuration.\n"
1094 "Your configuration changes were NOT saved."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001095 "\n\n"));
1096 return 1;
1097 }
1098 printf(_("\n\n"
Denis Vlasenko417e2402008-05-28 11:59:32 +00001099 "*** End of configuration.\n"
1100 "*** Execute 'make' to build the project or try 'make help'."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001101 "\n\n"));
1102 } else {
1103 fprintf(stderr, _("\n\n"
Denis Vlasenko417e2402008-05-28 11:59:32 +00001104 "Your configuration changes were NOT saved."
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001105 "\n\n"));
1106 }
1107
1108 return 0;
1109}