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