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