blob: b86c64f90c943676c45f8e814f3a86953b3a5e50 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 <ctype.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10#include <time.h>
11#include <sys/stat.h>
12
13#define LKC_DIRECT_LINK
14#include "lkc.h"
15
16static void conf(struct menu *menu);
17static void check_conf(struct menu *menu);
18
19enum {
20 ask_all,
21 ask_new,
22 ask_silent,
23 set_default,
24 set_yes,
25 set_mod,
26 set_no,
27 set_random
28} input_mode = ask_all;
29char *defconfig_file;
30
31static int indent = 1;
32static int valid_stdin = 1;
33static int conf_cnt;
J.A. Magallon48b9d032005-06-25 14:59:22 -070034static char line[128];
Linus Torvalds1da177e2005-04-16 15:20:36 -070035static struct menu *rootEntry;
36
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -070037static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
J.A. Magallon48b9d032005-06-25 14:59:22 -070039static void strip(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040{
J.A. Magallon48b9d032005-06-25 14:59:22 -070041 char *p = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 int l;
43
44 while ((isspace(*p)))
45 p++;
46 l = strlen(p);
47 if (p != str)
48 memmove(str, p, l + 1);
49 if (!l)
50 return;
51 p = str + l - 1;
52 while ((isspace(*p)))
53 *p-- = 0;
54}
55
56static void check_stdin(void)
57{
58 if (!valid_stdin && input_mode == ask_silent) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -070059 printf(_("aborted!\n\n"));
60 printf(_("Console input/output is redirected. "));
61 printf(_("Run 'make oldconfig' to update configuration.\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 exit(1);
63 }
64}
65
Ben Collins96e9dd12006-01-08 01:05:13 -080066static char *fgets_check_stream(char *s, int size, FILE *stream)
67{
68 char *ret = fgets(s, size, stream);
69
70 if (ret == NULL && feof(stream)) {
71 printf(_("aborted!\n\n"));
72 printf(_("Console input is closed. "));
73 printf(_("Run 'make oldconfig' to update configuration.\n\n"));
74 exit(1);
75 }
76
77 return ret;
78}
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static void conf_askvalue(struct symbol *sym, const char *def)
81{
82 enum symbol_type type = sym_get_type(sym);
83 tristate val;
84
85 if (!sym_has_value(sym))
86 printf("(NEW) ");
87
88 line[0] = '\n';
89 line[1] = 0;
90
91 if (!sym_is_changable(sym)) {
92 printf("%s\n", def);
93 line[0] = '\n';
94 line[1] = 0;
95 return;
96 }
97
98 switch (input_mode) {
Roman Zippel90389162005-11-08 21:34:49 -080099 case set_no:
100 case set_mod:
101 case set_yes:
102 case set_random:
103 if (sym_has_value(sym)) {
104 printf("%s\n", def);
105 return;
106 }
107 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 case ask_new:
109 case ask_silent:
110 if (sym_has_value(sym)) {
111 printf("%s\n", def);
112 return;
113 }
114 check_stdin();
115 case ask_all:
116 fflush(stdout);
Ben Collins96e9dd12006-01-08 01:05:13 -0800117 fgets_check_stream(line, 128, stdin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 return;
119 case set_default:
120 printf("%s\n", def);
121 return;
122 default:
123 break;
124 }
125
126 switch (type) {
127 case S_INT:
128 case S_HEX:
129 case S_STRING:
130 printf("%s\n", def);
131 return;
132 default:
133 ;
134 }
135 switch (input_mode) {
136 case set_yes:
137 if (sym_tristate_within_range(sym, yes)) {
138 line[0] = 'y';
139 line[1] = '\n';
140 line[2] = 0;
141 break;
142 }
143 case set_mod:
144 if (type == S_TRISTATE) {
145 if (sym_tristate_within_range(sym, mod)) {
146 line[0] = 'm';
147 line[1] = '\n';
148 line[2] = 0;
149 break;
150 }
151 } else {
152 if (sym_tristate_within_range(sym, yes)) {
153 line[0] = 'y';
154 line[1] = '\n';
155 line[2] = 0;
156 break;
157 }
158 }
159 case set_no:
160 if (sym_tristate_within_range(sym, no)) {
161 line[0] = 'n';
162 line[1] = '\n';
163 line[2] = 0;
164 break;
165 }
166 case set_random:
167 do {
168 val = (tristate)(random() % 3);
169 } while (!sym_tristate_within_range(sym, val));
170 switch (val) {
171 case no: line[0] = 'n'; break;
172 case mod: line[0] = 'm'; break;
173 case yes: line[0] = 'y'; break;
174 }
175 line[1] = '\n';
176 line[2] = 0;
177 break;
178 default:
179 break;
180 }
181 printf("%s", line);
182}
183
184int conf_string(struct menu *menu)
185{
186 struct symbol *sym = menu->sym;
187 const char *def, *help;
188
189 while (1) {
190 printf("%*s%s ", indent - 1, "", menu->prompt->text);
191 printf("(%s) ", sym->name);
192 def = sym_get_string_value(sym);
193 if (sym_get_string_value(sym))
194 printf("[%s] ", def);
195 conf_askvalue(sym, def);
196 switch (line[0]) {
197 case '\n':
198 break;
199 case '?':
200 /* print help */
201 if (line[1] == '\n') {
202 help = nohelp_text;
203 if (menu->sym->help)
204 help = menu->sym->help;
205 printf("\n%s\n", menu->sym->help);
206 def = NULL;
207 break;
208 }
209 default:
210 line[strlen(line)-1] = 0;
211 def = line;
212 }
213 if (def && sym_set_string_value(sym, def))
214 return 0;
215 }
216}
217
218static int conf_sym(struct menu *menu)
219{
220 struct symbol *sym = menu->sym;
221 int type;
222 tristate oldval, newval;
223 const char *help;
224
225 while (1) {
226 printf("%*s%s ", indent - 1, "", menu->prompt->text);
227 if (sym->name)
228 printf("(%s) ", sym->name);
229 type = sym_get_type(sym);
230 putchar('[');
231 oldval = sym_get_tristate_value(sym);
232 switch (oldval) {
233 case no:
234 putchar('N');
235 break;
236 case mod:
237 putchar('M');
238 break;
239 case yes:
240 putchar('Y');
241 break;
242 }
243 if (oldval != no && sym_tristate_within_range(sym, no))
244 printf("/n");
245 if (oldval != mod && sym_tristate_within_range(sym, mod))
246 printf("/m");
247 if (oldval != yes && sym_tristate_within_range(sym, yes))
248 printf("/y");
249 if (sym->help)
250 printf("/?");
251 printf("] ");
252 conf_askvalue(sym, sym_get_string_value(sym));
253 strip(line);
254
255 switch (line[0]) {
256 case 'n':
257 case 'N':
258 newval = no;
259 if (!line[1] || !strcmp(&line[1], "o"))
260 break;
261 continue;
262 case 'm':
263 case 'M':
264 newval = mod;
265 if (!line[1])
266 break;
267 continue;
268 case 'y':
269 case 'Y':
270 newval = yes;
271 if (!line[1] || !strcmp(&line[1], "es"))
272 break;
273 continue;
274 case 0:
275 newval = oldval;
276 break;
277 case '?':
278 goto help;
279 default:
280 continue;
281 }
282 if (sym_set_tristate_value(sym, newval))
283 return 0;
284help:
285 help = nohelp_text;
286 if (sym->help)
287 help = sym->help;
288 printf("\n%s\n", help);
289 }
290}
291
292static int conf_choice(struct menu *menu)
293{
294 struct symbol *sym, *def_sym;
295 struct menu *child;
296 int type;
297 bool is_new;
298
299 sym = menu->sym;
300 type = sym_get_type(sym);
301 is_new = !sym_has_value(sym);
302 if (sym_is_changable(sym)) {
303 conf_sym(menu);
304 sym_calc_value(sym);
305 switch (sym_get_tristate_value(sym)) {
306 case no:
307 return 1;
308 case mod:
309 return 0;
310 case yes:
311 break;
312 }
313 } else {
314 switch (sym_get_tristate_value(sym)) {
315 case no:
316 return 1;
317 case mod:
318 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
319 return 0;
320 case yes:
321 break;
322 }
323 }
324
325 while (1) {
326 int cnt, def;
327
328 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
329 def_sym = sym_get_choice_value(sym);
330 cnt = def = 0;
Roman Zippel40aee722006-04-09 17:26:39 +0200331 line[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 for (child = menu->list; child; child = child->next) {
333 if (!menu_is_visible(child))
334 continue;
335 if (!child->sym) {
336 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
337 continue;
338 }
339 cnt++;
340 if (child->sym == def_sym) {
341 def = cnt;
342 printf("%*c", indent, '>');
343 } else
344 printf("%*c", indent, ' ');
345 printf(" %d. %s", cnt, menu_get_prompt(child));
346 if (child->sym->name)
347 printf(" (%s)", child->sym->name);
348 if (!sym_has_value(child->sym))
349 printf(" (NEW)");
350 printf("\n");
351 }
352 printf("%*schoice", indent - 1, "");
353 if (cnt == 1) {
354 printf("[1]: 1\n");
355 goto conf_childs;
356 }
357 printf("[1-%d", cnt);
358 if (sym->help)
359 printf("?");
360 printf("]: ");
361 switch (input_mode) {
362 case ask_new:
363 case ask_silent:
364 if (!is_new) {
365 cnt = def;
366 printf("%d\n", cnt);
367 break;
368 }
369 check_stdin();
370 case ask_all:
371 fflush(stdout);
Ben Collins96e9dd12006-01-08 01:05:13 -0800372 fgets_check_stream(line, 128, stdin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 strip(line);
374 if (line[0] == '?') {
375 printf("\n%s\n", menu->sym->help ?
376 menu->sym->help : nohelp_text);
377 continue;
378 }
379 if (!line[0])
380 cnt = def;
381 else if (isdigit(line[0]))
382 cnt = atoi(line);
383 else
384 continue;
385 break;
386 case set_random:
387 def = (random() % cnt) + 1;
388 case set_default:
389 case set_yes:
390 case set_mod:
391 case set_no:
392 cnt = def;
393 printf("%d\n", cnt);
394 break;
395 }
396
397 conf_childs:
398 for (child = menu->list; child; child = child->next) {
399 if (!child->sym || !menu_is_visible(child))
400 continue;
401 if (!--cnt)
402 break;
403 }
404 if (!child)
405 continue;
406 if (line[strlen(line) - 1] == '?') {
407 printf("\n%s\n", child->sym->help ?
408 child->sym->help : nohelp_text);
409 continue;
410 }
411 sym_set_choice_value(sym, child->sym);
412 if (child->list) {
413 indent += 2;
414 conf(child->list);
415 indent -= 2;
416 }
417 return 1;
418 }
419}
420
421static void conf(struct menu *menu)
422{
423 struct symbol *sym;
424 struct property *prop;
425 struct menu *child;
426
427 if (!menu_is_visible(menu))
428 return;
429
430 sym = menu->sym;
431 prop = menu->prompt;
432 if (prop) {
433 const char *prompt;
434
435 switch (prop->type) {
436 case P_MENU:
437 if (input_mode == ask_silent && rootEntry != menu) {
438 check_conf(menu);
439 return;
440 }
441 case P_COMMENT:
442 prompt = menu_get_prompt(menu);
443 if (prompt)
444 printf("%*c\n%*c %s\n%*c\n",
445 indent, '*',
446 indent, '*', prompt,
447 indent, '*');
448 default:
449 ;
450 }
451 }
452
453 if (!sym)
454 goto conf_childs;
455
456 if (sym_is_choice(sym)) {
457 conf_choice(menu);
458 if (sym->curr.tri != mod)
459 return;
460 goto conf_childs;
461 }
462
463 switch (sym->type) {
464 case S_INT:
465 case S_HEX:
466 case S_STRING:
467 conf_string(menu);
468 break;
469 default:
470 conf_sym(menu);
471 break;
472 }
473
474conf_childs:
475 if (sym)
476 indent += 2;
477 for (child = menu->list; child; child = child->next)
478 conf(child);
479 if (sym)
480 indent -= 2;
481}
482
483static void check_conf(struct menu *menu)
484{
485 struct symbol *sym;
486 struct menu *child;
487
488 if (!menu_is_visible(menu))
489 return;
490
491 sym = menu->sym;
Roman Zippel3f23ca22005-11-08 21:34:48 -0800492 if (sym && !sym_has_value(sym)) {
493 if (sym_is_changable(sym) ||
494 (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 if (!conf_cnt++)
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700496 printf(_("*\n* Restart config...\n*\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 rootEntry = menu_get_parent_menu(menu);
498 conf(rootEntry);
499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501
502 for (child = menu->list; child; child = child->next)
503 check_conf(child);
504}
505
506int main(int ac, char **av)
507{
508 int i = 1;
509 const char *name;
510 struct stat tmpstat;
511
512 if (ac > i && av[i][0] == '-') {
513 switch (av[i++][1]) {
514 case 'o':
515 input_mode = ask_new;
516 break;
517 case 's':
518 input_mode = ask_silent;
519 valid_stdin = isatty(0) && isatty(1) && isatty(2);
520 break;
521 case 'd':
522 input_mode = set_default;
523 break;
524 case 'D':
525 input_mode = set_default;
526 defconfig_file = av[i++];
527 if (!defconfig_file) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700528 printf(_("%s: No default config file specified\n"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 av[0]);
530 exit(1);
531 }
532 break;
533 case 'n':
534 input_mode = set_no;
535 break;
536 case 'm':
537 input_mode = set_mod;
538 break;
539 case 'y':
540 input_mode = set_yes;
541 break;
542 case 'r':
543 input_mode = set_random;
544 srandom(time(NULL));
545 break;
546 case 'h':
547 case '?':
548 printf("%s [-o|-s] config\n", av[0]);
549 exit(0);
550 }
551 }
552 name = av[i];
553 if (!name) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700554 printf(_("%s: Kconfig file missing\n"), av[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 }
556 conf_parse(name);
557 //zconfdump(stdout);
558 switch (input_mode) {
559 case set_default:
560 if (!defconfig_file)
561 defconfig_file = conf_get_default_confname();
562 if (conf_read(defconfig_file)) {
563 printf("***\n"
564 "*** Can't find default configuration \"%s\"!\n"
565 "***\n", defconfig_file);
566 exit(1);
567 }
568 break;
569 case ask_silent:
570 if (stat(".config", &tmpstat)) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700571 printf(_("***\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 "*** You have not yet configured your kernel!\n"
573 "***\n"
574 "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
575 "*** \"make menuconfig\" or \"make xconfig\").\n"
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700576 "***\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 exit(1);
578 }
579 case ask_all:
580 case ask_new:
581 conf_read(NULL);
582 break;
Roman Zippel90389162005-11-08 21:34:49 -0800583 case set_no:
584 case set_mod:
585 case set_yes:
586 case set_random:
587 name = getenv("KCONFIG_ALLCONFIG");
588 if (name && !stat(name, &tmpstat)) {
589 conf_read_simple(name);
590 break;
591 }
592 switch (input_mode) {
593 case set_no: name = "allno.config"; break;
594 case set_mod: name = "allmod.config"; break;
595 case set_yes: name = "allyes.config"; break;
596 case set_random: name = "allrandom.config"; break;
597 default: break;
598 }
599 if (!stat(name, &tmpstat))
600 conf_read_simple(name);
601 else if (!stat("all.config", &tmpstat))
602 conf_read_simple("all.config");
603 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 default:
605 break;
606 }
607
608 if (input_mode != ask_silent) {
609 rootEntry = &rootmenu;
610 conf(&rootmenu);
611 if (input_mode == ask_all) {
612 input_mode = ask_silent;
613 valid_stdin = 1;
614 }
615 }
616 do {
617 conf_cnt = 0;
618 check_conf(&rootmenu);
619 } while (conf_cnt);
620 if (conf_write(NULL)) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700621 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return 1;
623 }
624 return 0;
625}