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