summaryrefslogtreecommitdiff
path: root/scripts/kconfig/mconf.c
Unidiff
Diffstat (limited to 'scripts/kconfig/mconf.c') (more/less context) (ignore whitespace changes)
-rw-r--r--scripts/kconfig/mconf.c711
1 files changed, 711 insertions, 0 deletions
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
new file mode 100644
index 0000000..84699be
--- a/dev/null
+++ b/scripts/kconfig/mconf.c
@@ -0,0 +1,711 @@
1/*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 */
5
6#include <sys/ioctl.h>
7#include <sys/wait.h>
8#include <ctype.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <signal.h>
12#include <stdarg.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16
17#define LKC_DIRECT_LINK
18#include "lkc.h"
19
20static char menu_backtitle[128];
21static const char menu_instructions[] =
22 "Arrow keys navigate the menu. "
23 "<Enter> selects submenus --->. "
24 "Highlighted letters are hotkeys. "
25 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
26 "Press <Esc><Esc> to exit, <?> for Help. "
27 "Legend: [*] built-in [ ] excluded <M> module < > module capable",
28radiolist_instructions[] =
29 "Use the arrow keys to navigate this window or "
30 "press the hotkey of the item you wish to select "
31 "followed by the <SPACE BAR>. "
32 "Press <?> for additional information about this option.",
33inputbox_instructions_int[] =
34 "Please enter a decimal value. "
35 "Fractions will not be accepted. "
36 "Use the <TAB> key to move from the input field to the buttons below it.",
37inputbox_instructions_hex[] =
38 "Please enter a hexadecimal value. "
39 "Use the <TAB> key to move from the input field to the buttons below it.",
40inputbox_instructions_string[] =
41 "Please enter a string value. "
42 "Use the <TAB> key to move from the input field to the buttons below it.",
43setmod_text[] =
44 "This feature depends on another which has been configured as a module.\n"
45 "As a result, this feature will be built as a module.",
46nohelp_text[] =
47 "There is no help available for this kernel option.\n",
48load_config_text[] =
49 "Enter the name of the configuration file you wish to load. "
50 "Accept the name shown to restore the configuration you "
51 "last retrieved. Leave blank to abort.",
52load_config_help[] =
53 "\n"
54 "For various reasons, one may wish to keep several different kernel\n"
55 "configurations available on a single machine.\n"
56 "\n"
57 "If you have saved a previous configuration in a file other than the\n"
58 "kernel's default, entering the name of the file here will allow you\n"
59 "to modify that configuration.\n"
60 "\n"
61 "If you are uncertain, then you have probably never used alternate\n"
62 "configuration files. You should therefor leave this blank to abort.\n",
63save_config_text[] =
64 "Enter a filename to which this configuration should be saved "
65 "as an alternate. Leave blank to abort.",
66save_config_help[] =
67 "\n"
68 "For various reasons, one may wish to keep different kernel\n"
69 "configurations available on a single machine.\n"
70 "\n"
71 "Entering a file name here will allow you to later retrieve, modify\n"
72 "and use the current configuration as an alternate to whatever\n"
73 "configuration options you have selected at that time.\n"
74 "\n"
75 "If you are uncertain what all this means then you should probably\n"
76 "leave this blank.\n"
77;
78
79static char buf[4096], *bufptr = buf;
80static char input_buf[4096];
81static char *args[1024], **argptr = args;
82static int indent = 0;
83static int rows, cols;
84static struct menu *current_menu;
85static int child_count;
86static int do_resize;
87
88static void conf(struct menu *menu);
89static void conf_choice(struct menu *menu);
90static void conf_string(struct menu *menu);
91static void conf_load(void);
92static void conf_save(void);
93static void show_textbox(const char *title, const char *text, int r, int c);
94static void show_helptext(const char *title, const char *text);
95static void show_help(struct menu *menu);
96static void show_readme(void);
97
98static void cprint_init(void);
99static int cprint1(const char *fmt, ...);
100static void cprint_done(void);
101static int cprint(const char *fmt, ...);
102
103static void init_wsize(void)
104{
105 struct winsize ws;
106
107 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
108 rows = 24;
109 cols = 80;
110 } else {
111 rows = ws.ws_row;
112 cols = ws.ws_col;
113 }
114
115 if (rows < 19 || cols < 80) {
116 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
117 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
118 exit(1);
119 }
120
121 rows -= 4;
122 cols -= 5;
123}
124
125static void cprint_init(void)
126{
127 bufptr = buf;
128 argptr = args;
129 memset(args, 0, sizeof(args));
130 indent = 0;
131 child_count = 0;
132 cprint("./scripts/lxdialog/lxdialog");
133 cprint("--backtitle");
134 cprint(menu_backtitle);
135}
136
137static int cprint1(const char *fmt, ...)
138{
139 va_list ap;
140 int res;
141
142 if (!*argptr)
143 *argptr = bufptr;
144 va_start(ap, fmt);
145 res = vsprintf(bufptr, fmt, ap);
146 va_end(ap);
147 bufptr += res;
148
149 return res;
150}
151
152static void cprint_done(void)
153{
154 *bufptr++ = 0;
155 argptr++;
156}
157
158static int cprint(const char *fmt, ...)
159{
160 va_list ap;
161 int res;
162
163 *argptr++ = bufptr;
164 va_start(ap, fmt);
165 res = vsprintf(bufptr, fmt, ap);
166 va_end(ap);
167 bufptr += res;
168 *bufptr++ = 0;
169
170 return res;
171}
172
173pid_t pid;
174
175static void winch_handler(int sig)
176{
177 if (!do_resize) {
178 kill(pid, SIGINT);
179 do_resize = 1;
180 }
181}
182
183static int exec_conf(void)
184{
185 int pipefd[2], stat, size;
186 struct sigaction sa;
187 sigset_t sset, osset;
188
189 sigemptyset(&sset);
190 sigaddset(&sset, SIGINT);
191 sigprocmask(SIG_BLOCK, &sset, &osset);
192
193 signal(SIGINT, SIG_DFL);
194
195 sa.sa_handler = winch_handler;
196 sigemptyset(&sa.sa_mask);
197 sa.sa_flags = SA_RESTART;
198 sigaction(SIGWINCH, &sa, NULL);
199
200 *argptr++ = NULL;
201
202 pipe(pipefd);
203 pid = fork();
204 if (pid == 0) {
205 sigprocmask(SIG_SETMASK, &osset, NULL);
206 dup2(pipefd[1], 2);
207 close(pipefd[0]);
208 close(pipefd[1]);
209 execv(args[0], args);
210 _exit(EXIT_FAILURE);
211 }
212
213 close(pipefd[1]);
214 bufptr = input_buf;
215 while (1) {
216 size = input_buf + sizeof(input_buf) - bufptr;
217 size = read(pipefd[0], bufptr, size);
218 if (size <= 0) {
219 if (size < 0) {
220 if (errno == EINTR || errno == EAGAIN)
221 continue;
222 perror("read");
223 }
224 break;
225 }
226 bufptr += size;
227 }
228 *bufptr++ = 0;
229 close(pipefd[0]);
230 waitpid(pid, &stat, 0);
231
232 if (do_resize) {
233 init_wsize();
234 do_resize = 0;
235 sigprocmask(SIG_SETMASK, &osset, NULL);
236 return -1;
237 }
238 if (WIFSIGNALED(stat)) {
239 printf("\finterrupted(%d)\n", WTERMSIG(stat));
240 exit(1);
241 }
242#if 0
243 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
244 sleep(1);
245#endif
246 sigpending(&sset);
247 if (sigismember(&sset, SIGINT)) {
248 printf("\finterrupted\n");
249 exit(1);
250 }
251 sigprocmask(SIG_SETMASK, &osset, NULL);
252
253 return WEXITSTATUS(stat);
254}
255
256static void build_conf(struct menu *menu)
257{
258 struct symbol *sym;
259 struct property *prop;
260 struct menu *child;
261 int type, tmp, doint = 2;
262 tristate val;
263 char ch;
264
265 if (!menu_is_visible(menu))
266 return;
267
268 sym = menu->sym;
269 prop = menu->prompt;
270 if (!sym) {
271 if (prop && menu != current_menu) {
272 const char *prompt = menu_get_prompt(menu);
273 switch (prop->type) {
274 case P_MENU:
275 child_count++;
276 cprint("m%p", menu);
277 if (menu->parent != &rootmenu)
278 cprint1(" %*c", indent + 1, ' ');
279 cprint1("%s --->", prompt);
280 cprint_done();
281 return;
282 default:
283 if (prompt) {
284 child_count++;
285 cprint(":%p", menu);
286 cprint("---%*c%s", indent + 1, ' ', prompt);
287 }
288 }
289 } else
290 doint = 0;
291 goto conf_childs;
292 }
293
294 type = sym_get_type(sym);
295 if (sym_is_choice(sym)) {
296 struct symbol *def_sym = sym_get_choice_value(sym);
297 struct menu *def_menu = NULL;
298
299 child_count++;
300 for (child = menu->list; child; child = child->next) {
301 if (menu_is_visible(child) && child->sym == def_sym)
302 def_menu = child;
303 }
304
305 val = sym_get_tristate_value(sym);
306 if (sym_is_changable(sym)) {
307 cprint("t%p", menu);
308 switch (type) {
309 case S_BOOLEAN:
310 cprint1("[%c]", val == no ? ' ' : '*');
311 break;
312 case S_TRISTATE:
313 switch (val) {
314 case yes: ch = '*'; break;
315 case mod: ch = 'M'; break;
316 default: ch = ' '; break;
317 }
318 cprint1("<%c>", ch);
319 break;
320 }
321 } else {
322 cprint("%c%p", def_menu ? 't' : ':', menu);
323 cprint1(" ");
324 }
325
326 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
327 if (val == yes) {
328 if (def_menu) {
329 cprint1(" (%s)", menu_get_prompt(def_menu));
330 cprint1(" --->");
331 cprint_done();
332 if (def_menu->list) {
333 indent += 2;
334 build_conf(def_menu);
335 indent -= 2;
336 }
337 } else
338 cprint_done();
339 return;
340 }
341 cprint_done();
342 } else {
343 child_count++;
344 val = sym_get_tristate_value(sym);
345 if (sym_is_choice_value(sym) && val == yes) {
346 cprint(":%p", menu);
347 cprint1(" ");
348 } else {
349 switch (type) {
350 case S_BOOLEAN:
351 cprint("t%p", menu);
352 cprint1("[%c]", val == no ? ' ' : '*');
353 break;
354 case S_TRISTATE:
355 cprint("t%p", menu);
356 switch (val) {
357 case yes: ch = '*'; break;
358 case mod: ch = 'M'; break;
359 default: ch = ' '; break;
360 }
361 cprint1("<%c>", ch);
362 break;
363 default:
364 cprint("s%p", menu);
365 tmp = cprint1("(%s)", sym_get_string_value(sym));
366 tmp = indent - tmp + 4;
367 if (tmp < 0)
368 tmp = 0;
369 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
370 sym_has_value(sym) ? "" : " (NEW)");
371 cprint_done();
372 goto conf_childs;
373 }
374 }
375 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
376 sym_has_value(sym) ? "" : " (NEW)");
377 cprint_done();
378 }
379
380conf_childs:
381 indent += doint;
382 for (child = menu->list; child; child = child->next)
383 build_conf(child);
384 indent -= doint;
385}
386
387static void conf(struct menu *menu)
388{
389 struct menu *submenu;
390 const char *prompt = menu_get_prompt(menu);
391 struct symbol *sym;
392 char active_entry[40];
393 int stat, type, i;
394
395 active_entry[0] = 0;
396 while (1) {
397 cprint_init();
398 cprint("--title");
399 cprint("%s", prompt ? prompt : "Main Menu");
400 cprint("--menu");
401 cprint(menu_instructions);
402 cprint("%d", rows);
403 cprint("%d", cols);
404 cprint("%d", rows - 10);
405 cprint("%s", active_entry);
406 current_menu = menu;
407 build_conf(menu);
408 if (!child_count)
409 break;
410 if (menu == &rootmenu) {
411 cprint(":");
412 cprint("--- ");
413 cprint("L");
414 cprint("Load an Alternate Configuration File");
415 cprint("S");
416 cprint("Save Configuration to an Alternate File");
417 }
418 stat = exec_conf();
419 if (stat < 0)
420 continue;
421
422 if (stat == 1 || stat == 255)
423 break;
424
425 type = input_buf[0];
426 if (!type)
427 continue;
428
429 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
430 ;
431 if (i >= sizeof(active_entry))
432 i = sizeof(active_entry) - 1;
433 input_buf[i] = 0;
434 strcpy(active_entry, input_buf);
435
436 sym = NULL;
437 submenu = NULL;
438 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
439 sym = submenu->sym;
440
441 switch (stat) {
442 case 0:
443 switch (type) {
444 case 'm':
445 conf(submenu);
446 break;
447 case 't':
448 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
449 conf_choice(submenu);
450 break;
451 case 's':
452 conf_string(submenu);
453 break;
454 case 'L':
455 conf_load();
456 break;
457 case 'S':
458 conf_save();
459 break;
460 }
461 break;
462 case 2:
463 if (sym)
464 show_help(submenu);
465 else
466 show_readme();
467 break;
468 case 3:
469 if (type == 't') {
470 if (sym_set_tristate_value(sym, yes))
471 break;
472 if (sym_set_tristate_value(sym, mod))
473 show_textbox(NULL, setmod_text, 6, 74);
474 }
475 break;
476 case 4:
477 if (type == 't')
478 sym_set_tristate_value(sym, no);
479 break;
480 case 5:
481 if (type == 't')
482 sym_set_tristate_value(sym, mod);
483 break;
484 case 6:
485 if (type == 't')
486 sym_toggle_tristate_value(sym);
487 break;
488 }
489 }
490}
491
492static void show_textbox(const char *title, const char *text, int r, int c)
493{
494 int fd;
495
496 fd = creat(".help.tmp", 0777);
497 write(fd, text, strlen(text));
498 close(fd);
499 do {
500 cprint_init();
501 if (title) {
502 cprint("--title");
503 cprint("%s", title);
504 }
505 cprint("--textbox");
506 cprint(".help.tmp");
507 cprint("%d", r);
508 cprint("%d", c);
509 } while (exec_conf() < 0);
510 unlink(".help.tmp");
511}
512
513static void show_helptext(const char *title, const char *text)
514{
515 show_textbox(title, text, rows, cols);
516}
517
518static void show_help(struct menu *menu)
519{
520 const char *help;
521
522 help = menu->sym->help;
523 if (!help)
524 help = nohelp_text;
525 show_helptext(menu_get_prompt(menu), help);
526}
527
528static void show_readme(void)
529{
530 do {
531 cprint_init();
532 cprint("--textbox");
533 cprint("scripts/README.Menuconfig");
534 cprint("%d", rows);
535 cprint("%d", cols);
536 } while (exec_conf() == -1);
537}
538
539static void conf_choice(struct menu *menu)
540{
541 const char *prompt = menu_get_prompt(menu);
542 struct menu *child;
543 struct symbol *active;
544 int stat;
545
546 while (1) {
547 cprint_init();
548 cprint("--title");
549 cprint("%s", prompt ? prompt : "Main Menu");
550 cprint("--radiolist");
551 cprint(radiolist_instructions);
552 cprint("15");
553 cprint("70");
554 cprint("6");
555
556 current_menu = menu;
557 active = sym_get_choice_value(menu->sym);
558 for (child = menu->list; child; child = child->next) {
559 if (!menu_is_visible(child))
560 continue;
561 cprint("%p", child);
562 cprint("%s", menu_get_prompt(child));
563 cprint(child->sym == active ? "ON" : "OFF");
564 }
565
566 stat = exec_conf();
567 switch (stat) {
568 case 0:
569 if (sscanf(input_buf, "%p", &menu) != 1)
570 break;
571 sym_set_tristate_value(menu->sym, yes);
572 return;
573 case 1:
574 show_help(menu);
575 break;
576 case 255:
577 return;
578 }
579 }
580}
581
582static void conf_string(struct menu *menu)
583{
584 const char *prompt = menu_get_prompt(menu);
585 int stat;
586
587 while (1) {
588 cprint_init();
589 cprint("--title");
590 cprint("%s", prompt ? prompt : "Main Menu");
591 cprint("--inputbox");
592 switch (sym_get_type(menu->sym)) {
593 case S_INT:
594 cprint(inputbox_instructions_int);
595 break;
596 case S_HEX:
597 cprint(inputbox_instructions_hex);
598 break;
599 case S_STRING:
600 cprint(inputbox_instructions_string);
601 break;
602 default:
603 /* panic? */;
604 }
605 cprint("10");
606 cprint("75");
607 cprint("%s", sym_get_string_value(menu->sym));
608 stat = exec_conf();
609 switch (stat) {
610 case 0:
611 if (sym_set_string_value(menu->sym, input_buf))
612 return;
613 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
614 break;
615 case 1:
616 show_help(menu);
617 break;
618 case 255:
619 return;
620 }
621 }
622}
623
624static void conf_load(void)
625{
626 int stat;
627
628 while (1) {
629 cprint_init();
630 cprint("--inputbox");
631 cprint(load_config_text);
632 cprint("11");
633 cprint("55");
634 cprint("%s", conf_filename);
635 stat = exec_conf();
636 switch(stat) {
637 case 0:
638 if (!input_buf[0])
639 return;
640 if (!conf_read(input_buf))
641 return;
642 show_textbox(NULL, "File does not exist!", 5, 38);
643 break;
644 case 1:
645 show_helptext("Load Alternate Configuration", load_config_help);
646 break;
647 case 255:
648 return;
649 }
650 }
651}
652
653static void conf_save(void)
654{
655 int stat;
656
657 while (1) {
658 cprint_init();
659 cprint("--inputbox");
660 cprint(save_config_text);
661 cprint("11");
662 cprint("55");
663 cprint("%s", conf_filename);
664 stat = exec_conf();
665 switch(stat) {
666 case 0:
667 if (!input_buf[0])
668 return;
669 if (!conf_write(input_buf))
670 return;
671 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
672 break;
673 case 1:
674 show_helptext("Save Alternate Configuration", save_config_help);
675 break;
676 case 255:
677 return;
678 }
679 }
680}
681
682int main(int ac, char **av)
683{
684 int stat;
685 conf_parse(av[1]);
686 conf_read(NULL);
687
688 sprintf(menu_backtitle, "Configuration");
689
690 init_wsize();
691 conf(&rootmenu);
692
693 do {
694 cprint_init();
695 cprint("--yesno");
696 cprint("Do you wish to save your new configuration?");
697 cprint("5");
698 cprint("60");
699 stat = exec_conf();
700 } while (stat < 0);
701
702 if (stat == 0) {
703 conf_write(NULL);
704 printf("\n\n"
705 "*** End of configuration.\n"
706 "*** Check the top-level Makefile for additional configuration.\n");
707 } else
708 printf("\n\nYour configuration changes were NOT saved.\n\n");
709
710 return 0;
711}