vserver 1.9.3
[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
9 #include <sys/ioctl.h>
10 #include <sys/wait.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <signal.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <termios.h>
20 #include <unistd.h>
21 #include <regex.h>
22
23 #define LKC_DIRECT_LINK
24 #include "lkc.h"
25
26 static char menu_backtitle[128];
27 static const char menu_instructions[] =
28         "Arrow keys navigate the menu.  "
29         "<Enter> selects submenus --->.  "
30         "Highlighted letters are hotkeys.  "
31         "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
32         "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
33         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
34 radiolist_instructions[] =
35         "Use the arrow keys to navigate this window or "
36         "press the hotkey of the item you wish to select "
37         "followed by the <SPACE BAR>. "
38         "Press <?> for additional information about this option.",
39 inputbox_instructions_int[] =
40         "Please enter a decimal value. "
41         "Fractions will not be accepted.  "
42         "Use the <TAB> key to move from the input field to the buttons below it.",
43 inputbox_instructions_hex[] =
44         "Please enter a hexadecimal value. "
45         "Use the <TAB> key to move from the input field to the buttons below it.",
46 inputbox_instructions_string[] =
47         "Please enter a string value. "
48         "Use the <TAB> key to move from the input field to the buttons below it.",
49 setmod_text[] =
50         "This feature depends on another which has been configured as a module.\n"
51         "As a result, this feature will be built as a module.",
52 nohelp_text[] =
53         "There is no help available for this kernel option.\n",
54 load_config_text[] =
55         "Enter the name of the configuration file you wish to load.  "
56         "Accept the name shown to restore the configuration you "
57         "last retrieved.  Leave blank to abort.",
58 load_config_help[] =
59         "\n"
60         "For various reasons, one may wish to keep several different kernel\n"
61         "configurations available on a single machine.\n"
62         "\n"
63         "If you have saved a previous configuration in a file other than the\n"
64         "kernel's default, entering the name of the file here will allow you\n"
65         "to modify that configuration.\n"
66         "\n"
67         "If you are uncertain, then you have probably never used alternate\n"
68         "configuration files.  You should therefor leave this blank to abort.\n",
69 save_config_text[] =
70         "Enter a filename to which this configuration should be saved "
71         "as an alternate.  Leave blank to abort.",
72 save_config_help[] =
73         "\n"
74         "For various reasons, one may wish to keep different kernel\n"
75         "configurations available on a single machine.\n"
76         "\n"
77         "Entering a file name here will allow you to later retrieve, modify\n"
78         "and use the current configuration as an alternate to whatever\n"
79         "configuration options you have selected at that time.\n"
80         "\n"
81         "If you are uncertain what all this means then you should probably\n"
82         "leave this blank.\n"
83 ;
84
85 static char buf[4096], *bufptr = buf;
86 static char input_buf[4096];
87 static char filename[PATH_MAX+1] = ".config";
88 static char *args[1024], **argptr = args;
89 static int indent;
90 static struct termios ios_org;
91 static int rows = 0, cols = 0;
92 static struct menu *current_menu;
93 static int child_count;
94 static int do_resize;
95 static int single_menu_mode;
96
97 static void conf(struct menu *menu);
98 static void conf_choice(struct menu *menu);
99 static void conf_string(struct menu *menu);
100 static void conf_load(void);
101 static void conf_save(void);
102 static void show_textbox(const char *title, const char *text, int r, int c);
103 static void show_helptext(const char *title, const char *text);
104 static void show_help(struct menu *menu);
105 static void show_readme(void);
106 static void show_file(const char *filename, const char *title, int r, int c);
107 static void show_expr(struct menu *menu, FILE *fp);
108 static void search_conf(char *pattern);
109 static int regex_match(const char *string, regex_t *re);
110
111 static void cprint_init(void);
112 static int cprint1(const char *fmt, ...);
113 static void cprint_done(void);
114 static int cprint(const char *fmt, ...);
115
116 static void init_wsize(void)
117 {
118         struct winsize ws;
119         char *env;
120
121         if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
122                 rows = ws.ws_row;
123                 cols = ws.ws_col;
124         }
125
126         if (!rows) {
127                 env = getenv("LINES");
128                 if (env)
129                         rows = atoi(env);
130                 if (!rows)
131                         rows = 24;
132         }
133         if (!cols) {
134                 env = getenv("COLUMNS");
135                 if (env)
136                         cols = atoi(env);
137                 if (!cols)
138                         cols = 80;
139         }
140
141         if (rows < 19 || cols < 80) {
142                 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
143                 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
144                 exit(1);
145         }
146
147         rows -= 4;
148         cols -= 5;
149 }
150
151 static void cprint_init(void)
152 {
153         bufptr = buf;
154         argptr = args;
155         memset(args, 0, sizeof(args));
156         indent = 0;
157         child_count = 0;
158         cprint("./scripts/lxdialog/lxdialog");
159         cprint("--backtitle");
160         cprint(menu_backtitle);
161 }
162
163 static int cprint1(const char *fmt, ...)
164 {
165         va_list ap;
166         int res;
167
168         if (!*argptr)
169                 *argptr = bufptr;
170         va_start(ap, fmt);
171         res = vsprintf(bufptr, fmt, ap);
172         va_end(ap);
173         bufptr += res;
174
175         return res;
176 }
177
178 static void cprint_done(void)
179 {
180         *bufptr++ = 0;
181         argptr++;
182 }
183
184 static int cprint(const char *fmt, ...)
185 {
186         va_list ap;
187         int res;
188
189         *argptr++ = bufptr;
190         va_start(ap, fmt);
191         res = vsprintf(bufptr, fmt, ap);
192         va_end(ap);
193         bufptr += res;
194         *bufptr++ = 0;
195
196         return res;
197 }
198
199 pid_t pid;
200
201 static void winch_handler(int sig)
202 {
203         if (!do_resize) {
204                 kill(pid, SIGINT);
205                 do_resize = 1;
206         }
207 }
208
209 static int exec_conf(void)
210 {
211         int pipefd[2], stat, size;
212         struct sigaction sa;
213         sigset_t sset, osset;
214
215         sigemptyset(&sset);
216         sigaddset(&sset, SIGINT);
217         sigprocmask(SIG_BLOCK, &sset, &osset);
218
219         signal(SIGINT, SIG_DFL);
220
221         sa.sa_handler = winch_handler;
222         sigemptyset(&sa.sa_mask);
223         sa.sa_flags = SA_RESTART;
224         sigaction(SIGWINCH, &sa, NULL);
225
226         *argptr++ = NULL;
227
228         pipe(pipefd);
229         pid = fork();
230         if (pid == 0) {
231                 sigprocmask(SIG_SETMASK, &osset, NULL);
232                 dup2(pipefd[1], 2);
233                 close(pipefd[0]);
234                 close(pipefd[1]);
235                 execv(args[0], args);
236                 _exit(EXIT_FAILURE);
237         }
238
239         close(pipefd[1]);
240         bufptr = input_buf;
241         while (1) {
242                 size = input_buf + sizeof(input_buf) - bufptr;
243                 size = read(pipefd[0], bufptr, size);
244                 if (size <= 0) {
245                         if (size < 0) {
246                                 if (errno == EINTR || errno == EAGAIN)
247                                         continue;
248                                 perror("read");
249                         }
250                         break;
251                 }
252                 bufptr += size;
253         }
254         *bufptr++ = 0;
255         close(pipefd[0]);
256         waitpid(pid, &stat, 0);
257
258         if (do_resize) {
259                 init_wsize();
260                 do_resize = 0;
261                 sigprocmask(SIG_SETMASK, &osset, NULL);
262                 return -1;
263         }
264         if (WIFSIGNALED(stat)) {
265                 printf("\finterrupted(%d)\n", WTERMSIG(stat));
266                 exit(1);
267         }
268 #if 0
269         printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
270         sleep(1);
271 #endif
272         sigpending(&sset);
273         if (sigismember(&sset, SIGINT)) {
274                 printf("\finterrupted\n");
275                 exit(1);
276         }
277         sigprocmask(SIG_SETMASK, &osset, NULL);
278
279         return WEXITSTATUS(stat);
280 }
281
282 static int regex_match(const char *string, regex_t *re)
283 {
284         int rc;
285
286         rc = regexec(re, string, (size_t) 0, NULL, 0);
287         if (rc)
288                 return 0;
289         return 1;
290 }
291
292 static void show_expr(struct menu *menu, FILE *fp)
293 {
294         bool hit = false;
295         fprintf(fp, "Depends:\n ");
296         if (menu->prompt->visible.expr) {
297                 if (!hit)
298                         hit = true;
299                 expr_fprint(menu->prompt->visible.expr, fp);
300         }
301         if (!hit)
302                 fprintf(fp, "None");
303         if (menu->sym) {
304                 struct property *prop;
305                 hit = false;
306                 fprintf(fp, "\nSelects:\n ");
307                 for_all_properties(menu->sym, prop, P_SELECT) {
308                         if (!hit)
309                                 hit = true;
310                         expr_fprint(prop->expr, fp);
311                 }
312                 if (!hit)
313                         fprintf(fp, "None");
314                 hit = false;
315                 fprintf(fp, "\nSelected by:\n ");
316                 if (menu->sym->rev_dep.expr) {
317                         hit = true;
318                         expr_fprint(menu->sym->rev_dep.expr, fp);
319                 }
320                 if (!hit)
321                         fprintf(fp, "None");
322         }
323 }
324
325 static void search_conf(char *pattern)
326 {
327         struct symbol *sym = NULL;
328         struct menu *menu[32] = { 0 };
329         struct property *prop = NULL;
330         FILE *fp = NULL;
331         bool hit = false;
332         int i, j, k, l;
333         regex_t re;
334
335         if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB))
336                 return;
337
338         fp = fopen(".search.tmp", "w");
339         if (fp == NULL) {
340                 perror("fopen");
341                 return;
342         }
343         for_all_symbols(i, sym) {
344                 if (!sym->name)
345                         continue;
346                 if (!regex_match(sym->name, &re))
347                         continue;
348                 for_all_prompts(sym, prop) {
349                         struct menu *submenu = prop->menu;
350                         if (!submenu)
351                                 continue;
352                         j = 0;
353                         hit = false;
354                         while (submenu) {
355                                 menu[j++] = submenu;
356                                 submenu = submenu->parent;
357                         }
358                         if (j > 0) {
359                                 if (!hit)
360                                         hit = true;
361                                 fprintf(fp, "%s (%s)\n", prop->text, sym->name);
362                                 fprintf(fp, "Location:\n");
363                         }
364                         for (k = j-2, l=1; k > 0; k--, l++) {
365                                 const char *prompt = menu_get_prompt(menu[k]);
366                                 if (menu[k]->sym)
367                                         fprintf(fp, "%*c-> %s (%s)\n",
368                                                                 l, ' ',
369                                                                 prompt,
370                                                                 menu[k]->sym->name);
371                                 else
372                                         fprintf(fp, "%*c-> %s\n",
373                                                                 l, ' ',
374                                                                 prompt);
375                         }
376                         if (hit) {
377                                 show_expr(menu[0], fp);
378                                 fprintf(fp, "\n\n\n");
379                         }
380                 }
381         }
382         if (!hit)
383                 fprintf(fp, "No matches found.");
384         regfree(&re);
385         fclose(fp);
386         show_file(".search.tmp", "Search Results", rows, cols);
387         unlink(".search.tmp");
388 }
389
390 static void build_conf(struct menu *menu)
391 {
392         struct symbol *sym;
393         struct property *prop;
394         struct menu *child;
395         int type, tmp, doint = 2;
396         tristate val;
397         char ch;
398
399         if (!menu_is_visible(menu))
400                 return;
401
402         sym = menu->sym;
403         prop = menu->prompt;
404         if (!sym) {
405                 if (prop && menu != current_menu) {
406                         const char *prompt = menu_get_prompt(menu);
407                         switch (prop->type) {
408                         case P_MENU:
409                                 child_count++;
410                                 cprint("m%p", menu);
411
412                                 if (single_menu_mode) {
413                                         cprint1("%s%*c%s",
414                                                 menu->data ? "-->" : "++>",
415                                                 indent + 1, ' ', prompt);
416                                 } else
417                                         cprint1("   %*c%s  --->", indent + 1, ' ', prompt);
418
419                                 cprint_done();
420                                 if (single_menu_mode && menu->data)
421                                         goto conf_childs;
422                                 return;
423                         default:
424                                 if (prompt) {
425                                         child_count++;
426                                         cprint(":%p", menu);
427                                         cprint("---%*c%s", indent + 1, ' ', prompt);
428                                 }
429                         }
430                 } else
431                         doint = 0;
432                 goto conf_childs;
433         }
434
435         type = sym_get_type(sym);
436         if (sym_is_choice(sym)) {
437                 struct symbol *def_sym = sym_get_choice_value(sym);
438                 struct menu *def_menu = NULL;
439
440                 child_count++;
441                 for (child = menu->list; child; child = child->next) {
442                         if (menu_is_visible(child) && child->sym == def_sym)
443                                 def_menu = child;
444                 }
445
446                 val = sym_get_tristate_value(sym);
447                 if (sym_is_changable(sym)) {
448                         cprint("t%p", menu);
449                         switch (type) {
450                         case S_BOOLEAN:
451                                 cprint1("[%c]", val == no ? ' ' : '*');
452                                 break;
453                         case S_TRISTATE:
454                                 switch (val) {
455                                 case yes: ch = '*'; break;
456                                 case mod: ch = 'M'; break;
457                                 default:  ch = ' '; break;
458                                 }
459                                 cprint1("<%c>", ch);
460                                 break;
461                         }
462                 } else {
463                         cprint("%c%p", def_menu ? 't' : ':', menu);
464                         cprint1("   ");
465                 }
466
467                 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
468                 if (val == yes) {
469                         if (def_menu) {
470                                 cprint1(" (%s)", menu_get_prompt(def_menu));
471                                 cprint1("  --->");
472                                 cprint_done();
473                                 if (def_menu->list) {
474                                         indent += 2;
475                                         build_conf(def_menu);
476                                         indent -= 2;
477                                 }
478                         } else
479                                 cprint_done();
480                         return;
481                 }
482                 cprint_done();
483         } else {
484                 if (menu == current_menu) {
485                         cprint(":%p", menu);
486                         cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
487                         goto conf_childs;
488                 }
489                 child_count++;
490                 val = sym_get_tristate_value(sym);
491                 if (sym_is_choice_value(sym) && val == yes) {
492                         cprint(":%p", menu);
493                         cprint1("   ");
494                 } else {
495                         switch (type) {
496                         case S_BOOLEAN:
497                                 cprint("t%p", menu);
498                                 if (sym_is_changable(sym))
499                                         cprint1("[%c]", val == no ? ' ' : '*');
500                                 else
501                                         cprint1("---");
502                                 break;
503                         case S_TRISTATE:
504                                 cprint("t%p", menu);
505                                 switch (val) {
506                                 case yes: ch = '*'; break;
507                                 case mod: ch = 'M'; break;
508                                 default:  ch = ' '; break;
509                                 }
510                                 if (sym_is_changable(sym))
511                                         cprint1("<%c>", ch);
512                                 else
513                                         cprint1("---");
514                                 break;
515                         default:
516                                 cprint("s%p", menu);
517                                 tmp = cprint1("(%s)", sym_get_string_value(sym));
518                                 tmp = indent - tmp + 4;
519                                 if (tmp < 0)
520                                         tmp = 0;
521                                 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
522                                         (sym_has_value(sym) || !sym_is_changable(sym)) ?
523                                         "" : " (NEW)");
524                                 cprint_done();
525                                 goto conf_childs;
526                         }
527                 }
528                 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
529                         (sym_has_value(sym) || !sym_is_changable(sym)) ?
530                         "" : " (NEW)");
531                 if (menu->prompt->type == P_MENU) {
532                         cprint1("  --->");
533                         cprint_done();
534                         return;
535                 }
536                 cprint_done();
537         }
538
539 conf_childs:
540         indent += doint;
541         for (child = menu->list; child; child = child->next)
542                 build_conf(child);
543         indent -= doint;
544 }
545
546 static void conf(struct menu *menu)
547 {
548         struct menu *submenu;
549         const char *prompt = menu_get_prompt(menu);
550         struct symbol *sym;
551         char active_entry[40];
552         int stat, type, i;
553
554         unlink("lxdialog.scrltmp");
555         active_entry[0] = 0;
556         while (1) {
557                 cprint_init();
558                 cprint("--title");
559                 cprint("%s", prompt ? prompt : "Main Menu");
560                 cprint("--menu");
561                 cprint(menu_instructions);
562                 cprint("%d", rows);
563                 cprint("%d", cols);
564                 cprint("%d", rows - 10);
565                 cprint("%s", active_entry);
566                 current_menu = menu;
567                 build_conf(menu);
568                 if (!child_count)
569                         break;
570                 if (menu == &rootmenu) {
571                         cprint(":");
572                         cprint("--- ");
573                         cprint("L");
574                         cprint("    Load an Alternate Configuration File");
575                         cprint("S");
576                         cprint("    Save Configuration to an Alternate File");
577                 }
578                 stat = exec_conf();
579                 if (stat == 26) {
580                         char *pattern;
581
582                         if (!strlen(input_buf))
583                                 continue;
584                         pattern = malloc(sizeof(char)*sizeof(input_buf));
585                         if (pattern == NULL) {
586                                 perror("malloc");
587                                 continue;
588                         }
589                         for (i = 0; input_buf[i]; i++)
590                                 pattern[i] = toupper(input_buf[i]);
591                         pattern[i] = '\0';
592                         search_conf(pattern);
593                         free(pattern);
594                         continue;
595                 }
596                 if (stat < 0)
597                         continue;
598
599                 if (stat == 1 || stat == 255)
600                         break;
601
602                 type = input_buf[0];
603                 if (!type)
604                         continue;
605
606                 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
607                         ;
608                 if (i >= sizeof(active_entry))
609                         i = sizeof(active_entry) - 1;
610                 input_buf[i] = 0;
611                 strcpy(active_entry, input_buf);
612
613                 sym = NULL;
614                 submenu = NULL;
615                 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
616                         sym = submenu->sym;
617
618                 switch (stat) {
619                 case 0:
620                         switch (type) {
621                         case 'm':
622                                 if (single_menu_mode)
623                                         submenu->data = (void *) (long) !submenu->data;
624                                 else
625                                         conf(submenu);
626                                 break;
627                         case 't':
628                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
629                                         conf_choice(submenu);
630                                 else if (submenu->prompt->type == P_MENU)
631                                         conf(submenu);
632                                 break;
633                         case 's':
634                                 conf_string(submenu);
635                                 break;
636                         case 'L':
637                                 conf_load();
638                                 break;
639                         case 'S':
640                                 conf_save();
641                                 break;
642                         }
643                         break;
644                 case 2:
645                         if (sym)
646                                 show_help(submenu);
647                         else
648                                 show_readme();
649                         break;
650                 case 3:
651                         if (type == 't') {
652                                 if (sym_set_tristate_value(sym, yes))
653                                         break;
654                                 if (sym_set_tristate_value(sym, mod))
655                                         show_textbox(NULL, setmod_text, 6, 74);
656                         }
657                         break;
658                 case 4:
659                         if (type == 't')
660                                 sym_set_tristate_value(sym, no);
661                         break;
662                 case 5:
663                         if (type == 't')
664                                 sym_set_tristate_value(sym, mod);
665                         break;
666                 case 6:
667                         if (type == 't')
668                                 sym_toggle_tristate_value(sym);
669                         else if (type == 'm')
670                                 conf(submenu);
671                         break;
672                 }
673         }
674 }
675
676 static void show_textbox(const char *title, const char *text, int r, int c)
677 {
678         int fd;
679
680         fd = creat(".help.tmp", 0777);
681         write(fd, text, strlen(text));
682         close(fd);
683         show_file(".help.tmp", title, r, c);
684         unlink(".help.tmp");
685 }
686
687 static void show_helptext(const char *title, const char *text)
688 {
689         show_textbox(title, text, rows, cols);
690 }
691
692 static void show_help(struct menu *menu)
693 {
694         const char *help;
695         char *helptext;
696         struct symbol *sym = menu->sym;
697
698         help = sym->help;
699         if (!help)
700                 help = nohelp_text;
701         if (sym->name) {
702                 helptext = malloc(strlen(sym->name) + strlen(help) + 16);
703                 sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help);
704                 show_helptext(menu_get_prompt(menu), helptext);
705                 free(helptext);
706         } else
707                 show_helptext(menu_get_prompt(menu), help);
708 }
709
710 static void show_readme(void)
711 {
712         show_file("scripts/README.Menuconfig", NULL, rows, cols);
713 }
714
715 static void show_file(const char *filename, const char *title, int r, int c)
716 {
717         do {
718                 cprint_init();
719                 if (title) {
720                         cprint("--title");
721                         cprint("%s", title);
722                 }
723                 cprint("--textbox");
724                 cprint("%s", filename);
725                 cprint("%d", r);
726                 cprint("%d", c);
727         } while (exec_conf() < 0);
728 }
729
730 static void conf_choice(struct menu *menu)
731 {
732         const char *prompt = menu_get_prompt(menu);
733         struct menu *child;
734         struct symbol *active;
735         int stat;
736
737         active = sym_get_choice_value(menu->sym);
738         while (1) {
739                 cprint_init();
740                 cprint("--title");
741                 cprint("%s", prompt ? prompt : "Main Menu");
742                 cprint("--radiolist");
743                 cprint(radiolist_instructions);
744                 cprint("15");
745                 cprint("70");
746                 cprint("6");
747
748                 current_menu = menu;
749                 for (child = menu->list; child; child = child->next) {
750                         if (!menu_is_visible(child))
751                                 continue;
752                         cprint("%p", child);
753                         cprint("%s", menu_get_prompt(child));
754                         if (child->sym == sym_get_choice_value(menu->sym))
755                                 cprint("ON");
756                         else if (child->sym == active)
757                                 cprint("SELECTED");
758                         else
759                                 cprint("OFF");
760                 }
761
762                 stat = exec_conf();
763                 switch (stat) {
764                 case 0:
765                         if (sscanf(input_buf, "%p", &child) != 1)
766                                 break;
767                         sym_set_tristate_value(child->sym, yes);
768                         return;
769                 case 1:
770                         if (sscanf(input_buf, "%p", &child) == 1) {
771                                 show_help(child);
772                                 active = child->sym;
773                         } else
774                                 show_help(menu);
775                         break;
776                 case 255:
777                         return;
778                 }
779         }
780 }
781
782 static void conf_string(struct menu *menu)
783 {
784         const char *prompt = menu_get_prompt(menu);
785         int stat;
786
787         while (1) {
788                 cprint_init();
789                 cprint("--title");
790                 cprint("%s", prompt ? prompt : "Main Menu");
791                 cprint("--inputbox");
792                 switch (sym_get_type(menu->sym)) {
793                 case S_INT:
794                         cprint(inputbox_instructions_int);
795                         break;
796                 case S_HEX:
797                         cprint(inputbox_instructions_hex);
798                         break;
799                 case S_STRING:
800                         cprint(inputbox_instructions_string);
801                         break;
802                 default:
803                         /* panic? */;
804                 }
805                 cprint("10");
806                 cprint("75");
807                 cprint("%s", sym_get_string_value(menu->sym));
808                 stat = exec_conf();
809                 switch (stat) {
810                 case 0:
811                         if (sym_set_string_value(menu->sym, input_buf))
812                                 return;
813                         show_textbox(NULL, "You have made an invalid entry.", 5, 43);
814                         break;
815                 case 1:
816                         show_help(menu);
817                         break;
818                 case 255:
819                         return;
820                 }
821         }
822 }
823
824 static void conf_load(void)
825 {
826         int stat;
827
828         while (1) {
829                 cprint_init();
830                 cprint("--inputbox");
831                 cprint(load_config_text);
832                 cprint("11");
833                 cprint("55");
834                 cprint("%s", filename);
835                 stat = exec_conf();
836                 switch(stat) {
837                 case 0:
838                         if (!input_buf[0])
839                                 return;
840                         if (!conf_read(input_buf))
841                                 return;
842                         show_textbox(NULL, "File does not exist!", 5, 38);
843                         break;
844                 case 1:
845                         show_helptext("Load Alternate Configuration", load_config_help);
846                         break;
847                 case 255:
848                         return;
849                 }
850         }
851 }
852
853 static void conf_save(void)
854 {
855         int stat;
856
857         while (1) {
858                 cprint_init();
859                 cprint("--inputbox");
860                 cprint(save_config_text);
861                 cprint("11");
862                 cprint("55");
863                 cprint("%s", filename);
864                 stat = exec_conf();
865                 switch(stat) {
866                 case 0:
867                         if (!input_buf[0])
868                                 return;
869                         if (!conf_write(input_buf))
870                                 return;
871                         show_textbox(NULL, "Can't create file!  Probably a nonexistent directory.", 5, 60);
872                         break;
873                 case 1:
874                         show_helptext("Save Alternate Configuration", save_config_help);
875                         break;
876                 case 255:
877                         return;
878                 }
879         }
880 }
881
882 static void conf_cleanup(void)
883 {
884         tcsetattr(1, TCSAFLUSH, &ios_org);
885         unlink(".help.tmp");
886         unlink("lxdialog.scrltmp");
887 }
888
889 int main(int ac, char **av)
890 {
891         struct symbol *sym;
892         char *mode;
893         int stat;
894
895         conf_parse(av[1]);
896         conf_read(NULL);
897
898         sym = sym_lookup("KERNELRELEASE", 0);
899         sym_calc_value(sym);
900         sprintf(menu_backtitle, "Linux Kernel v%s Configuration",
901                 sym_get_string_value(sym));
902
903         mode = getenv("MENUCONFIG_MODE");
904         if (mode) {
905                 if (!strcasecmp(mode, "single_menu"))
906                         single_menu_mode = 1;
907         }
908
909         tcgetattr(1, &ios_org);
910         atexit(conf_cleanup);
911         init_wsize();
912         conf(&rootmenu);
913
914         do {
915                 cprint_init();
916                 cprint("--yesno");
917                 cprint("Do you wish to save your new kernel configuration?");
918                 cprint("5");
919                 cprint("60");
920                 stat = exec_conf();
921         } while (stat < 0);
922
923         if (stat == 0) {
924                 if (conf_write(NULL)) {
925                         fprintf(stderr, "\n\n"
926                                 "Error during writing of the kernel configuration.\n"
927                                 "Your kernel configuration changes were NOT saved."
928                                 "\n\n");
929                         return 1;
930                 }
931                 printf("\n\n"
932                         "*** End of Linux kernel configuration.\n"
933                         "*** Execute 'make' to build the kernel or try 'make help'."
934                         "\n\n");
935         } else {
936                 fprintf(stderr, "\n\n"
937                         "Your kernel configuration changes were NOT saved."
938                         "\n\n");
939         }
940
941         return 0;
942 }