blob: 59926739d1691c537eb1c76a544c603c8004e283 [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"
Sam Ravnborg45897212006-07-24 22:04:04 +0200162"default mode.\n"
163"\n"
164"Different color themes available\n"
165"--------------------------------\n"
166"It is possible to select different color themes using the variable\n"
167"MENUCONFIG_COLOR. To select a theme use:\n"
168"\n"
169"make MENUCONFIG_COLOR=<theme> menuconfig\n"
170"\n"
171"Available themes are\n"
172" mono => selects colors suitable for monochrome displays\n"
173" blackbg => selects a color scheme with black background\n"
Sam Ravnborg350b5b72006-07-24 22:19:51 +0200174" classic => theme with blue background. The classic look\n"
175" bluetitle => a LCD friendly version of classic. (default)\n"
Sam Ravnborg45897212006-07-24 22:04:04 +0200176"\n"),
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700177menu_instructions[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 "Arrow keys navigate the menu. "
179 "<Enter> selects submenus --->. "
180 "Highlighted letters are hotkeys. "
181 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
182 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700183 "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
184radiolist_instructions[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 "Use the arrow keys to navigate this window or "
186 "press the hotkey of the item you wish to select "
187 "followed by the <SPACE BAR>. "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700188 "Press <?> for additional information about this option."),
189inputbox_instructions_int[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 "Please enter a decimal value. "
191 "Fractions will not be accepted. "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700192 "Use the <TAB> key to move from the input field to the buttons below it."),
193inputbox_instructions_hex[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 "Please enter a hexadecimal value. "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700195 "Use the <TAB> key to move from the input field to the buttons below it."),
196inputbox_instructions_string[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 "Please enter a string value. "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700198 "Use the <TAB> key to move from the input field to the buttons below it."),
199setmod_text[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 "This feature depends on another which has been configured as a module.\n"
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700201 "As a result, this feature will be built as a module."),
202nohelp_text[] = N_(
203 "There is no help available for this kernel option.\n"),
204load_config_text[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 "Enter the name of the configuration file you wish to load. "
206 "Accept the name shown to restore the configuration you "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700207 "last retrieved. Leave blank to abort."),
208load_config_help[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 "\n"
210 "For various reasons, one may wish to keep several different kernel\n"
211 "configurations available on a single machine.\n"
212 "\n"
213 "If you have saved a previous configuration in a file other than the\n"
214 "kernel's default, entering the name of the file here will allow you\n"
215 "to modify that configuration.\n"
216 "\n"
217 "If you are uncertain, then you have probably never used alternate\n"
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700218 "configuration files. You should therefor leave this blank to abort.\n"),
219save_config_text[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 "Enter a filename to which this configuration should be saved "
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700221 "as an alternate. Leave blank to abort."),
222save_config_help[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 "\n"
224 "For various reasons, one may wish to keep different kernel\n"
225 "configurations available on a single machine.\n"
226 "\n"
227 "Entering a file name here will allow you to later retrieve, modify\n"
228 "and use the current configuration as an alternate to whatever\n"
229 "configuration options you have selected at that time.\n"
230 "\n"
231 "If you are uncertain what all this means then you should probably\n"
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700232 "leave this blank.\n"),
233search_help[] = N_(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 "\n"
235 "Search for CONFIG_ symbols and display their relations.\n"
Randy Dunlap503af332005-10-30 15:02:15 -0800236 "Regular expressions are allowed.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 "Example: search for \"^FOO\"\n"
238 "Result:\n"
239 "-----------------------------------------------------------------\n"
240 "Symbol: FOO [=m]\n"
241 "Prompt: Foo bus is used to drive the bar HW\n"
242 "Defined at drivers/pci/Kconfig:47\n"
243 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
244 "Location:\n"
245 " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
246 " -> PCI support (PCI [=y])\n"
247 " -> PCI access mode (<choice> [=y])\n"
248 "Selects: LIBCRC32\n"
249 "Selected by: BAR\n"
250 "-----------------------------------------------------------------\n"
251 "o The line 'Prompt:' shows the text used in the menu structure for\n"
252 " this CONFIG_ symbol\n"
253 "o The 'Defined at' line tell at what file / line number the symbol\n"
254 " is defined\n"
255 "o The 'Depends on:' line tell what symbols needs to be defined for\n"
256 " this symbol to be visible in the menu (selectable)\n"
257 "o The 'Location:' lines tell where in the menu structure this symbol\n"
258 " is located\n"
259 " A location followed by a [=y] indicate that this is a selectable\n"
260 " menu item - and current value is displayed inside brackets.\n"
261 "o The 'Selects:' line tell what symbol will be automatically\n"
262 " selected if this symbol is selected (y or m)\n"
263 "o The 'Selected by' line tell what symbol has selected this symbol\n"
264 "\n"
265 "Only relevant lines are shown.\n"
266 "\n\n"
267 "Search examples:\n"
268 "Examples: USB => find all CONFIG_ symbols containing USB\n"
269 " ^USB => find all CONFIG_ symbols starting with USB\n"
270 " USB$ => find all CONFIG_ symbols ending with USB\n"
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700271 "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
J.A. Magallon48b9d032005-06-25 14:59:22 -0700273static char buf[4096], *bufptr = buf;
274static char input_buf[4096];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275static char filename[PATH_MAX+1] = ".config";
276static char *args[1024], **argptr = args;
277static int indent;
278static struct termios ios_org;
279static int rows = 0, cols = 0;
280static struct menu *current_menu;
281static int child_count;
282static int do_resize;
283static int single_menu_mode;
284
285static void conf(struct menu *menu);
286static void conf_choice(struct menu *menu);
287static void conf_string(struct menu *menu);
288static void conf_load(void);
289static void conf_save(void);
290static void show_textbox(const char *title, const char *text, int r, int c);
291static void show_helptext(const char *title, const char *text);
292static void show_help(struct menu *menu);
293static void show_file(const char *filename, const char *title, int r, int c);
294
295static void cprint_init(void);
296static int cprint1(const char *fmt, ...);
297static void cprint_done(void);
298static int cprint(const char *fmt, ...);
299
300static void init_wsize(void)
301{
302 struct winsize ws;
303 char *env;
304
305 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
306 rows = ws.ws_row;
307 cols = ws.ws_col;
308 }
309
310 if (!rows) {
311 env = getenv("LINES");
312 if (env)
313 rows = atoi(env);
314 if (!rows)
315 rows = 24;
316 }
317 if (!cols) {
318 env = getenv("COLUMNS");
319 if (env)
320 cols = atoi(env);
321 if (!cols)
322 cols = 80;
323 }
324
325 if (rows < 19 || cols < 80) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700326 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
327 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 exit(1);
329 }
330
331 rows -= 4;
332 cols -= 5;
333}
334
335static void cprint_init(void)
336{
337 bufptr = buf;
338 argptr = args;
339 memset(args, 0, sizeof(args));
340 indent = 0;
341 child_count = 0;
Sam Ravnborg6f6046c2005-12-16 21:35:19 +0100342 cprint("./scripts/kconfig/lxdialog/lxdialog");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 cprint("--backtitle");
344 cprint(menu_backtitle);
345}
346
347static int cprint1(const char *fmt, ...)
348{
349 va_list ap;
350 int res;
351
352 if (!*argptr)
353 *argptr = bufptr;
354 va_start(ap, fmt);
355 res = vsprintf(bufptr, fmt, ap);
356 va_end(ap);
357 bufptr += res;
358
359 return res;
360}
361
362static void cprint_done(void)
363{
364 *bufptr++ = 0;
365 argptr++;
366}
367
368static int cprint(const char *fmt, ...)
369{
370 va_list ap;
371 int res;
372
373 *argptr++ = bufptr;
374 va_start(ap, fmt);
375 res = vsprintf(bufptr, fmt, ap);
376 va_end(ap);
377 bufptr += res;
378 *bufptr++ = 0;
379
380 return res;
381}
382
383static void get_prompt_str(struct gstr *r, struct property *prop)
384{
385 int i, j;
386 struct menu *submenu[8], *menu;
387
388 str_printf(r, "Prompt: %s\n", prop->text);
389 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
390 prop->menu->lineno);
391 if (!expr_is_yes(prop->visible.expr)) {
392 str_append(r, " Depends on: ");
393 expr_gstr_print(prop->visible.expr, r);
394 str_append(r, "\n");
395 }
396 menu = prop->menu->parent;
397 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
398 submenu[i++] = menu;
399 if (i > 0) {
400 str_printf(r, " Location:\n");
401 for (j = 4; --i >= 0; j += 2) {
402 menu = submenu[i];
403 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
404 if (menu->sym) {
405 str_printf(r, " (%s [=%s])", menu->sym->name ?
406 menu->sym->name : "<choice>",
407 sym_get_string_value(menu->sym));
408 }
409 str_append(r, "\n");
410 }
411 }
412}
413
414static void get_symbol_str(struct gstr *r, struct symbol *sym)
415{
416 bool hit;
417 struct property *prop;
418
419 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
420 sym_get_string_value(sym));
421 for_all_prompts(sym, prop)
422 get_prompt_str(r, prop);
423 hit = false;
424 for_all_properties(sym, prop, P_SELECT) {
425 if (!hit) {
426 str_append(r, " Selects: ");
427 hit = true;
428 } else
429 str_printf(r, " && ");
430 expr_gstr_print(prop->expr, r);
431 }
432 if (hit)
433 str_append(r, "\n");
434 if (sym->rev_dep.expr) {
435 str_append(r, " Selected by: ");
436 expr_gstr_print(sym->rev_dep.expr, r);
437 str_append(r, "\n");
438 }
439 str_append(r, "\n\n");
440}
441
442static struct gstr get_relations_str(struct symbol **sym_arr)
443{
444 struct symbol *sym;
445 struct gstr res = str_new();
446 int i;
447
448 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
449 get_symbol_str(&res, sym);
450 if (!i)
451 str_append(&res, "No matches found.\n");
452 return res;
453}
454
455pid_t pid;
456
457static void winch_handler(int sig)
458{
459 if (!do_resize) {
460 kill(pid, SIGINT);
461 do_resize = 1;
462 }
463}
464
465static int exec_conf(void)
466{
467 int pipefd[2], stat, size;
468 struct sigaction sa;
469 sigset_t sset, osset;
470
471 sigemptyset(&sset);
472 sigaddset(&sset, SIGINT);
473 sigprocmask(SIG_BLOCK, &sset, &osset);
474
475 signal(SIGINT, SIG_DFL);
476
477 sa.sa_handler = winch_handler;
478 sigemptyset(&sa.sa_mask);
479 sa.sa_flags = SA_RESTART;
480 sigaction(SIGWINCH, &sa, NULL);
481
482 *argptr++ = NULL;
483
484 pipe(pipefd);
485 pid = fork();
486 if (pid == 0) {
487 sigprocmask(SIG_SETMASK, &osset, NULL);
488 dup2(pipefd[1], 2);
489 close(pipefd[0]);
490 close(pipefd[1]);
491 execv(args[0], args);
492 _exit(EXIT_FAILURE);
493 }
494
495 close(pipefd[1]);
496 bufptr = input_buf;
497 while (1) {
498 size = input_buf + sizeof(input_buf) - bufptr;
499 size = read(pipefd[0], bufptr, size);
500 if (size <= 0) {
501 if (size < 0) {
502 if (errno == EINTR || errno == EAGAIN)
503 continue;
504 perror("read");
505 }
506 break;
507 }
508 bufptr += size;
509 }
510 *bufptr++ = 0;
511 close(pipefd[0]);
512 waitpid(pid, &stat, 0);
513
514 if (do_resize) {
515 init_wsize();
516 do_resize = 0;
517 sigprocmask(SIG_SETMASK, &osset, NULL);
518 return -1;
519 }
520 if (WIFSIGNALED(stat)) {
521 printf("\finterrupted(%d)\n", WTERMSIG(stat));
522 exit(1);
523 }
524#if 0
525 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
526 sleep(1);
527#endif
528 sigpending(&sset);
529 if (sigismember(&sset, SIGINT)) {
530 printf("\finterrupted\n");
531 exit(1);
532 }
533 sigprocmask(SIG_SETMASK, &osset, NULL);
534
535 return WEXITSTATUS(stat);
536}
537
538static void search_conf(void)
539{
540 struct symbol **sym_arr;
541 int stat;
542 struct gstr res;
543
544again:
545 cprint_init();
546 cprint("--title");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700547 cprint(_("Search Configuration Parameter"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 cprint("--inputbox");
Randy Dunlap503af332005-10-30 15:02:15 -0800549 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 cprint("10");
551 cprint("75");
552 cprint("");
553 stat = exec_conf();
554 if (stat < 0)
555 goto again;
556 switch (stat) {
557 case 0:
558 break;
559 case 1:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700560 show_helptext(_("Search Configuration"), search_help);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 goto again;
562 default:
563 return;
564 }
565
566 sym_arr = sym_re_search(input_buf);
567 res = get_relations_str(sym_arr);
568 free(sym_arr);
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700569 show_textbox(_("Search Results"), str_get(&res), 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 str_free(&res);
571}
572
573static void build_conf(struct menu *menu)
574{
575 struct symbol *sym;
576 struct property *prop;
577 struct menu *child;
578 int type, tmp, doint = 2;
579 tristate val;
580 char ch;
581
582 if (!menu_is_visible(menu))
583 return;
584
585 sym = menu->sym;
586 prop = menu->prompt;
587 if (!sym) {
588 if (prop && menu != current_menu) {
589 const char *prompt = menu_get_prompt(menu);
590 switch (prop->type) {
591 case P_MENU:
592 child_count++;
593 cprint("m%p", menu);
594
595 if (single_menu_mode) {
596 cprint1("%s%*c%s",
597 menu->data ? "-->" : "++>",
598 indent + 1, ' ', prompt);
599 } else
600 cprint1(" %*c%s --->", indent + 1, ' ', prompt);
601
602 cprint_done();
603 if (single_menu_mode && menu->data)
604 goto conf_childs;
605 return;
606 default:
607 if (prompt) {
608 child_count++;
609 cprint(":%p", menu);
610 cprint("---%*c%s", indent + 1, ' ', prompt);
611 }
612 }
613 } else
614 doint = 0;
615 goto conf_childs;
616 }
617
618 type = sym_get_type(sym);
619 if (sym_is_choice(sym)) {
620 struct symbol *def_sym = sym_get_choice_value(sym);
621 struct menu *def_menu = NULL;
622
623 child_count++;
624 for (child = menu->list; child; child = child->next) {
625 if (menu_is_visible(child) && child->sym == def_sym)
626 def_menu = child;
627 }
628
629 val = sym_get_tristate_value(sym);
630 if (sym_is_changable(sym)) {
631 cprint("t%p", menu);
632 switch (type) {
633 case S_BOOLEAN:
634 cprint1("[%c]", val == no ? ' ' : '*');
635 break;
636 case S_TRISTATE:
637 switch (val) {
638 case yes: ch = '*'; break;
639 case mod: ch = 'M'; break;
640 default: ch = ' '; break;
641 }
642 cprint1("<%c>", ch);
643 break;
644 }
645 } else {
646 cprint("%c%p", def_menu ? 't' : ':', menu);
647 cprint1(" ");
648 }
649
650 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
651 if (val == yes) {
652 if (def_menu) {
653 cprint1(" (%s)", menu_get_prompt(def_menu));
654 cprint1(" --->");
655 cprint_done();
656 if (def_menu->list) {
657 indent += 2;
658 build_conf(def_menu);
659 indent -= 2;
660 }
661 } else
662 cprint_done();
663 return;
664 }
665 cprint_done();
666 } else {
667 if (menu == current_menu) {
668 cprint(":%p", menu);
669 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
670 goto conf_childs;
671 }
672 child_count++;
673 val = sym_get_tristate_value(sym);
674 if (sym_is_choice_value(sym) && val == yes) {
675 cprint(":%p", menu);
676 cprint1(" ");
677 } else {
678 switch (type) {
679 case S_BOOLEAN:
680 cprint("t%p", menu);
681 if (sym_is_changable(sym))
682 cprint1("[%c]", val == no ? ' ' : '*');
683 else
684 cprint1("---");
685 break;
686 case S_TRISTATE:
687 cprint("t%p", menu);
688 switch (val) {
689 case yes: ch = '*'; break;
690 case mod: ch = 'M'; break;
691 default: ch = ' '; break;
692 }
693 if (sym_is_changable(sym))
694 cprint1("<%c>", ch);
695 else
696 cprint1("---");
697 break;
698 default:
699 cprint("s%p", menu);
700 tmp = cprint1("(%s)", sym_get_string_value(sym));
701 tmp = indent - tmp + 4;
702 if (tmp < 0)
703 tmp = 0;
704 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
705 (sym_has_value(sym) || !sym_is_changable(sym)) ?
706 "" : " (NEW)");
707 cprint_done();
708 goto conf_childs;
709 }
710 }
711 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
712 (sym_has_value(sym) || !sym_is_changable(sym)) ?
713 "" : " (NEW)");
714 if (menu->prompt->type == P_MENU) {
715 cprint1(" --->");
716 cprint_done();
717 return;
718 }
719 cprint_done();
720 }
721
722conf_childs:
723 indent += doint;
724 for (child = menu->list; child; child = child->next)
725 build_conf(child);
726 indent -= doint;
727}
728
729static void conf(struct menu *menu)
730{
731 struct menu *submenu;
732 const char *prompt = menu_get_prompt(menu);
733 struct symbol *sym;
734 char active_entry[40];
735 int stat, type, i;
736
737 unlink("lxdialog.scrltmp");
738 active_entry[0] = 0;
739 while (1) {
740 cprint_init();
741 cprint("--title");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700742 cprint("%s", prompt ? prompt : _("Main Menu"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 cprint("--menu");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700744 cprint(_(menu_instructions));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 cprint("%d", rows);
746 cprint("%d", cols);
747 cprint("%d", rows - 10);
748 cprint("%s", active_entry);
749 current_menu = menu;
750 build_conf(menu);
751 if (!child_count)
752 break;
753 if (menu == &rootmenu) {
754 cprint(":");
755 cprint("--- ");
756 cprint("L");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700757 cprint(_(" Load an Alternate Configuration File"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 cprint("S");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700759 cprint(_(" Save Configuration to an Alternate File"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
761 stat = exec_conf();
762 if (stat < 0)
763 continue;
764
765 if (stat == 1 || stat == 255)
766 break;
767
768 type = input_buf[0];
769 if (!type)
770 continue;
771
772 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
773 ;
774 if (i >= sizeof(active_entry))
775 i = sizeof(active_entry) - 1;
776 input_buf[i] = 0;
777 strcpy(active_entry, input_buf);
778
779 sym = NULL;
780 submenu = NULL;
781 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
782 sym = submenu->sym;
783
784 switch (stat) {
785 case 0:
786 switch (type) {
787 case 'm':
788 if (single_menu_mode)
789 submenu->data = (void *) (long) !submenu->data;
790 else
791 conf(submenu);
792 break;
793 case 't':
794 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
795 conf_choice(submenu);
796 else if (submenu->prompt->type == P_MENU)
797 conf(submenu);
798 break;
799 case 's':
800 conf_string(submenu);
801 break;
802 case 'L':
803 conf_load();
804 break;
805 case 'S':
806 conf_save();
807 break;
808 }
809 break;
810 case 2:
811 if (sym)
812 show_help(submenu);
813 else
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700814 show_helptext("README", _(mconf_readme));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 break;
816 case 3:
817 if (type == 't') {
818 if (sym_set_tristate_value(sym, yes))
819 break;
820 if (sym_set_tristate_value(sym, mod))
821 show_textbox(NULL, setmod_text, 6, 74);
822 }
823 break;
824 case 4:
825 if (type == 't')
826 sym_set_tristate_value(sym, no);
827 break;
828 case 5:
829 if (type == 't')
830 sym_set_tristate_value(sym, mod);
831 break;
832 case 6:
833 if (type == 't')
834 sym_toggle_tristate_value(sym);
835 else if (type == 'm')
836 conf(submenu);
837 break;
838 case 7:
839 search_conf();
840 break;
841 }
842 }
843}
844
845static void show_textbox(const char *title, const char *text, int r, int c)
846{
847 int fd;
848
849 fd = creat(".help.tmp", 0777);
850 write(fd, text, strlen(text));
851 close(fd);
852 show_file(".help.tmp", title, r, c);
853 unlink(".help.tmp");
854}
855
856static void show_helptext(const char *title, const char *text)
857{
858 show_textbox(title, text, 0, 0);
859}
860
861static void show_help(struct menu *menu)
862{
863 struct gstr help = str_new();
864 struct symbol *sym = menu->sym;
865
866 if (sym->help)
867 {
868 if (sym->name) {
869 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700870 str_append(&help, _(sym->help));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 str_append(&help, "\n");
872 }
873 } else {
874 str_append(&help, nohelp_text);
875 }
876 get_symbol_str(&help, sym);
877 show_helptext(menu_get_prompt(menu), str_get(&help));
878 str_free(&help);
879}
880
881static void show_file(const char *filename, const char *title, int r, int c)
882{
883 do {
884 cprint_init();
885 if (title) {
886 cprint("--title");
887 cprint("%s", title);
888 }
889 cprint("--textbox");
890 cprint("%s", filename);
891 cprint("%d", r ? r : rows);
892 cprint("%d", c ? c : cols);
893 } while (exec_conf() < 0);
894}
895
896static void conf_choice(struct menu *menu)
897{
898 const char *prompt = menu_get_prompt(menu);
899 struct menu *child;
900 struct symbol *active;
901 int stat;
902
903 active = sym_get_choice_value(menu->sym);
904 while (1) {
905 cprint_init();
906 cprint("--title");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700907 cprint("%s", prompt ? prompt : _("Main Menu"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 cprint("--radiolist");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700909 cprint(_(radiolist_instructions));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 cprint("15");
911 cprint("70");
912 cprint("6");
913
914 current_menu = menu;
915 for (child = menu->list; child; child = child->next) {
916 if (!menu_is_visible(child))
917 continue;
918 cprint("%p", child);
919 cprint("%s", menu_get_prompt(child));
920 if (child->sym == sym_get_choice_value(menu->sym))
921 cprint("ON");
922 else if (child->sym == active)
923 cprint("SELECTED");
924 else
925 cprint("OFF");
926 }
927
928 stat = exec_conf();
929 switch (stat) {
930 case 0:
931 if (sscanf(input_buf, "%p", &child) != 1)
932 break;
933 sym_set_tristate_value(child->sym, yes);
934 return;
935 case 1:
936 if (sscanf(input_buf, "%p", &child) == 1) {
937 show_help(child);
938 active = child->sym;
939 } else
940 show_help(menu);
941 break;
942 case 255:
943 return;
944 }
945 }
946}
947
948static void conf_string(struct menu *menu)
949{
950 const char *prompt = menu_get_prompt(menu);
951 int stat;
952
953 while (1) {
954 cprint_init();
955 cprint("--title");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700956 cprint("%s", prompt ? prompt : _("Main Menu"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 cprint("--inputbox");
958 switch (sym_get_type(menu->sym)) {
959 case S_INT:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700960 cprint(_(inputbox_instructions_int));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 break;
962 case S_HEX:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700963 cprint(_(inputbox_instructions_hex));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 break;
965 case S_STRING:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700966 cprint(_(inputbox_instructions_string));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 break;
968 default:
969 /* panic? */;
970 }
971 cprint("10");
972 cprint("75");
973 cprint("%s", sym_get_string_value(menu->sym));
974 stat = exec_conf();
975 switch (stat) {
976 case 0:
977 if (sym_set_string_value(menu->sym, input_buf))
978 return;
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700979 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 break;
981 case 1:
982 show_help(menu);
983 break;
984 case 255:
985 return;
986 }
987 }
988}
989
990static void conf_load(void)
991{
992 int stat;
993
994 while (1) {
995 cprint_init();
996 cprint("--inputbox");
997 cprint(load_config_text);
998 cprint("11");
999 cprint("55");
1000 cprint("%s", filename);
1001 stat = exec_conf();
1002 switch(stat) {
1003 case 0:
1004 if (!input_buf[0])
1005 return;
1006 if (!conf_read(input_buf))
1007 return;
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001008 show_textbox(NULL, _("File does not exist!"), 5, 38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 break;
1010 case 1:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001011 show_helptext(_("Load Alternate Configuration"), load_config_help);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 break;
1013 case 255:
1014 return;
1015 }
1016 }
1017}
1018
1019static void conf_save(void)
1020{
1021 int stat;
1022
1023 while (1) {
1024 cprint_init();
1025 cprint("--inputbox");
1026 cprint(save_config_text);
1027 cprint("11");
1028 cprint("55");
1029 cprint("%s", filename);
1030 stat = exec_conf();
1031 switch(stat) {
1032 case 0:
1033 if (!input_buf[0])
1034 return;
1035 if (!conf_write(input_buf))
1036 return;
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001037 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 break;
1039 case 1:
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001040 show_helptext(_("Save Alternate Configuration"), save_config_help);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 break;
1042 case 255:
1043 return;
1044 }
1045 }
1046}
1047
1048static void conf_cleanup(void)
1049{
1050 tcsetattr(1, TCSAFLUSH, &ios_org);
1051 unlink(".help.tmp");
1052 unlink("lxdialog.scrltmp");
1053}
1054
1055int main(int ac, char **av)
1056{
1057 struct symbol *sym;
1058 char *mode;
1059 int stat;
1060
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001061 setlocale(LC_ALL, "");
1062 bindtextdomain(PACKAGE, LOCALEDIR);
1063 textdomain(PACKAGE);
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 conf_parse(av[1]);
1066 conf_read(NULL);
1067
Sam Ravnborg2244cbd2006-01-16 12:12:12 +01001068 sym = sym_lookup("KERNELVERSION", 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 sym_calc_value(sym);
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001070 sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 sym_get_string_value(sym));
1072
1073 mode = getenv("MENUCONFIG_MODE");
1074 if (mode) {
1075 if (!strcasecmp(mode, "single_menu"))
1076 single_menu_mode = 1;
1077 }
1078
1079 tcgetattr(1, &ios_org);
1080 atexit(conf_cleanup);
1081 init_wsize();
1082 conf(&rootmenu);
1083
1084 do {
1085 cprint_init();
1086 cprint("--yesno");
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001087 cprint(_("Do you wish to save your new kernel configuration?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 cprint("5");
1089 cprint("60");
1090 stat = exec_conf();
1091 } while (stat < 0);
1092
1093 if (stat == 0) {
1094 if (conf_write(NULL)) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001095 fprintf(stderr, _("\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 "Error during writing of the kernel configuration.\n"
1097 "Your kernel configuration changes were NOT saved."
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001098 "\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return 1;
1100 }
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001101 printf(_("\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 "*** End of Linux kernel configuration.\n"
1103 "*** Execute 'make' to build the kernel or try 'make help'."
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001104 "\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 } else {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001106 fprintf(stderr, _("\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 "Your kernel configuration changes were NOT saved."
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -07001108 "\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 }
1110
1111 return 0;
1112}