kconfig/lxdialog: add a new theme bluetitle which is now default
[linux-2.6.git] / scripts / kconfig / mconf.c
1 /*
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
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>
23 #include <locale.h>
24
25 #define LKC_DIRECT_LINK
26 #include "lkc.h"
27
28 static char menu_backtitle[128];
29 static const char mconf_readme[] = N_(
30 "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"
162 "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"
174 " classic    => theme with blue background. The classic look\n"
175 " bluetitle  => a LCD friendly version of classic. (default)\n"
176 "\n"),
177 menu_instructions[] = N_(
178         "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.  "
183         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
184 radiolist_instructions[] = N_(
185         "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>. "
188         "Press <?> for additional information about this option."),
189 inputbox_instructions_int[] = N_(
190         "Please enter a decimal value. "
191         "Fractions will not be accepted.  "
192         "Use the <TAB> key to move from the input field to the buttons below it."),
193 inputbox_instructions_hex[] = N_(
194         "Please enter a hexadecimal value. "
195         "Use the <TAB> key to move from the input field to the buttons below it."),
196 inputbox_instructions_string[] = N_(
197         "Please enter a string value. "
198         "Use the <TAB> key to move from the input field to the buttons below it."),
199 setmod_text[] = N_(
200         "This feature depends on another which has been configured as a module.\n"
201         "As a result, this feature will be built as a module."),
202 nohelp_text[] = N_(
203         "There is no help available for this kernel option.\n"),
204 load_config_text[] = N_(
205         "Enter the name of the configuration file you wish to load.  "
206         "Accept the name shown to restore the configuration you "
207         "last retrieved.  Leave blank to abort."),
208 load_config_help[] = N_(
209         "\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"
218         "configuration files.  You should therefor leave this blank to abort.\n"),
219 save_config_text[] = N_(
220         "Enter a filename to which this configuration should be saved "
221         "as an alternate.  Leave blank to abort."),
222 save_config_help[] = N_(
223         "\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"
232         "leave this blank.\n"),
233 search_help[] = N_(
234         "\n"
235         "Search for CONFIG_ symbols and display their relations.\n"
236         "Regular expressions are allowed.\n"
237         "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"
271         "\n");
272
273 static char buf[4096], *bufptr = buf;
274 static char input_buf[4096];
275 static char filename[PATH_MAX+1] = ".config";
276 static char *args[1024], **argptr = args;
277 static int indent;
278 static struct termios ios_org;
279 static int rows = 0, cols = 0;
280 static struct menu *current_menu;
281 static int child_count;
282 static int do_resize;
283 static int single_menu_mode;
284
285 static void conf(struct menu *menu);
286 static void conf_choice(struct menu *menu);
287 static void conf_string(struct menu *menu);
288 static void conf_load(void);
289 static void conf_save(void);
290 static void show_textbox(const char *title, const char *text, int r, int c);
291 static void show_helptext(const char *title, const char *text);
292 static void show_help(struct menu *menu);
293 static void show_file(const char *filename, const char *title, int r, int c);
294
295 static void cprint_init(void);
296 static int cprint1(const char *fmt, ...);
297 static void cprint_done(void);
298 static int cprint(const char *fmt, ...);
299
300 static 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) {
326                 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"));
328                 exit(1);
329         }
330
331         rows -= 4;
332         cols -= 5;
333 }
334
335 static void cprint_init(void)
336 {
337         bufptr = buf;
338         argptr = args;
339         memset(args, 0, sizeof(args));
340         indent = 0;
341         child_count = 0;
342         cprint("./scripts/kconfig/lxdialog/lxdialog");
343         cprint("--backtitle");
344         cprint(menu_backtitle);
345 }
346
347 static 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
362 static void cprint_done(void)
363 {
364         *bufptr++ = 0;
365         argptr++;
366 }
367
368 static 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
383 static 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
414 static 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
442 static 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
455 pid_t pid;
456
457 static void winch_handler(int sig)
458 {
459         if (!do_resize) {
460                 kill(pid, SIGINT);
461                 do_resize = 1;
462         }
463 }
464
465 static 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
538 static void search_conf(void)
539 {
540         struct symbol **sym_arr;
541         int stat;
542         struct gstr res;
543
544 again:
545         cprint_init();
546         cprint("--title");
547         cprint(_("Search Configuration Parameter"));
548         cprint("--inputbox");
549         cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
550         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:
560                 show_helptext(_("Search Configuration"), search_help);
561                 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);
569         show_textbox(_("Search Results"), str_get(&res), 0, 0);
570         str_free(&res);
571 }
572
573 static 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
722 conf_childs:
723         indent += doint;
724         for (child = menu->list; child; child = child->next)
725                 build_conf(child);
726         indent -= doint;
727 }
728
729 static 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");
742                 cprint("%s", prompt ? prompt : _("Main Menu"));
743                 cprint("--menu");
744                 cprint(_(menu_instructions));
745                 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");
757                         cprint(_("    Load an Alternate Configuration File"));
758                         cprint("S");
759                         cprint(_("    Save Configuration to an Alternate File"));
760                 }
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
814                                 show_helptext("README", _(mconf_readme));
815                         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
845 static 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
856 static void show_helptext(const char *title, const char *text)
857 {
858         show_textbox(title, text, 0, 0);
859 }
860
861 static 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);
870                         str_append(&help, _(sym->help));
871                         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
881 static 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
896 static 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");
907                 cprint("%s", prompt ? prompt : _("Main Menu"));
908                 cprint("--radiolist");
909                 cprint(_(radiolist_instructions));
910                 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
948 static 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");
956                 cprint("%s", prompt ? prompt : _("Main Menu"));
957                 cprint("--inputbox");
958                 switch (sym_get_type(menu->sym)) {
959                 case S_INT:
960                         cprint(_(inputbox_instructions_int));
961                         break;
962                 case S_HEX:
963                         cprint(_(inputbox_instructions_hex));
964                         break;
965                 case S_STRING:
966                         cprint(_(inputbox_instructions_string));
967                         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;
979                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
980                         break;
981                 case 1:
982                         show_help(menu);
983                         break;
984                 case 255:
985                         return;
986                 }
987         }
988 }
989
990 static 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;
1008                         show_textbox(NULL, _("File does not exist!"), 5, 38);
1009                         break;
1010                 case 1:
1011                         show_helptext(_("Load Alternate Configuration"), load_config_help);
1012                         break;
1013                 case 255:
1014                         return;
1015                 }
1016         }
1017 }
1018
1019 static 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;
1037                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
1038                         break;
1039                 case 1:
1040                         show_helptext(_("Save Alternate Configuration"), save_config_help);
1041                         break;
1042                 case 255:
1043                         return;
1044                 }
1045         }
1046 }
1047
1048 static void conf_cleanup(void)
1049 {
1050         tcsetattr(1, TCSAFLUSH, &ios_org);
1051         unlink(".help.tmp");
1052         unlink("lxdialog.scrltmp");
1053 }
1054
1055 int main(int ac, char **av)
1056 {
1057         struct symbol *sym;
1058         char *mode;
1059         int stat;
1060
1061         setlocale(LC_ALL, "");
1062         bindtextdomain(PACKAGE, LOCALEDIR);
1063         textdomain(PACKAGE);
1064
1065         conf_parse(av[1]);
1066         conf_read(NULL);
1067
1068         sym = sym_lookup("KERNELVERSION", 0);
1069         sym_calc_value(sym);
1070         sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
1071                 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");
1087                 cprint(_("Do you wish to save your new kernel configuration?"));
1088                 cprint("5");
1089                 cprint("60");
1090                 stat = exec_conf();
1091         } while (stat < 0);
1092
1093         if (stat == 0) {
1094                 if (conf_write(NULL)) {
1095                         fprintf(stderr, _("\n\n"
1096                                 "Error during writing of the kernel configuration.\n"
1097                                 "Your kernel configuration changes were NOT saved."
1098                                 "\n\n"));
1099                         return 1;
1100                 }
1101                 printf(_("\n\n"
1102                         "*** End of Linux kernel configuration.\n"
1103                         "*** Execute 'make' to build the kernel or try 'make help'."
1104                         "\n\n"));
1105         } else {
1106                 fprintf(stderr, _("\n\n"
1107                         "Your kernel configuration changes were NOT saved."
1108                         "\n\n"));
1109         }
1110
1111         return 0;
1112 }