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