blob: 8ba5d29d3d42d1221b2fdc1b6e137ca750513da8 [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
66static void conf_askvalue(struct symbol *sym, const char *def)
67{
68 enum symbol_type type = sym_get_type(sym);
69 tristate val;
70
71 if (!sym_has_value(sym))
72 printf("(NEW) ");
73
74 line[0] = '\n';
75 line[1] = 0;
76
77 if (!sym_is_changable(sym)) {
78 printf("%s\n", def);
79 line[0] = '\n';
80 line[1] = 0;
81 return;
82 }
83
84 switch (input_mode) {
Roman Zippel90389162005-11-08 21:34:49 -080085 case set_no:
86 case set_mod:
87 case set_yes:
88 case set_random:
89 if (sym_has_value(sym)) {
90 printf("%s\n", def);
91 return;
92 }
93 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 case ask_new:
95 case ask_silent:
96 if (sym_has_value(sym)) {
97 printf("%s\n", def);
98 return;
99 }
100 check_stdin();
101 case ask_all:
102 fflush(stdout);
103 fgets(line, 128, stdin);
104 return;
105 case set_default:
106 printf("%s\n", def);
107 return;
108 default:
109 break;
110 }
111
112 switch (type) {
113 case S_INT:
114 case S_HEX:
115 case S_STRING:
116 printf("%s\n", def);
117 return;
118 default:
119 ;
120 }
121 switch (input_mode) {
122 case set_yes:
123 if (sym_tristate_within_range(sym, yes)) {
124 line[0] = 'y';
125 line[1] = '\n';
126 line[2] = 0;
127 break;
128 }
129 case set_mod:
130 if (type == S_TRISTATE) {
131 if (sym_tristate_within_range(sym, mod)) {
132 line[0] = 'm';
133 line[1] = '\n';
134 line[2] = 0;
135 break;
136 }
137 } else {
138 if (sym_tristate_within_range(sym, yes)) {
139 line[0] = 'y';
140 line[1] = '\n';
141 line[2] = 0;
142 break;
143 }
144 }
145 case set_no:
146 if (sym_tristate_within_range(sym, no)) {
147 line[0] = 'n';
148 line[1] = '\n';
149 line[2] = 0;
150 break;
151 }
152 case set_random:
153 do {
154 val = (tristate)(random() % 3);
155 } while (!sym_tristate_within_range(sym, val));
156 switch (val) {
157 case no: line[0] = 'n'; break;
158 case mod: line[0] = 'm'; break;
159 case yes: line[0] = 'y'; break;
160 }
161 line[1] = '\n';
162 line[2] = 0;
163 break;
164 default:
165 break;
166 }
167 printf("%s", line);
168}
169
170int conf_string(struct menu *menu)
171{
172 struct symbol *sym = menu->sym;
173 const char *def, *help;
174
175 while (1) {
176 printf("%*s%s ", indent - 1, "", menu->prompt->text);
177 printf("(%s) ", sym->name);
178 def = sym_get_string_value(sym);
179 if (sym_get_string_value(sym))
180 printf("[%s] ", def);
181 conf_askvalue(sym, def);
182 switch (line[0]) {
183 case '\n':
184 break;
185 case '?':
186 /* print help */
187 if (line[1] == '\n') {
188 help = nohelp_text;
189 if (menu->sym->help)
190 help = menu->sym->help;
191 printf("\n%s\n", menu->sym->help);
192 def = NULL;
193 break;
194 }
195 default:
196 line[strlen(line)-1] = 0;
197 def = line;
198 }
199 if (def && sym_set_string_value(sym, def))
200 return 0;
201 }
202}
203
204static int conf_sym(struct menu *menu)
205{
206 struct symbol *sym = menu->sym;
207 int type;
208 tristate oldval, newval;
209 const char *help;
210
211 while (1) {
212 printf("%*s%s ", indent - 1, "", menu->prompt->text);
213 if (sym->name)
214 printf("(%s) ", sym->name);
215 type = sym_get_type(sym);
216 putchar('[');
217 oldval = sym_get_tristate_value(sym);
218 switch (oldval) {
219 case no:
220 putchar('N');
221 break;
222 case mod:
223 putchar('M');
224 break;
225 case yes:
226 putchar('Y');
227 break;
228 }
229 if (oldval != no && sym_tristate_within_range(sym, no))
230 printf("/n");
231 if (oldval != mod && sym_tristate_within_range(sym, mod))
232 printf("/m");
233 if (oldval != yes && sym_tristate_within_range(sym, yes))
234 printf("/y");
235 if (sym->help)
236 printf("/?");
237 printf("] ");
238 conf_askvalue(sym, sym_get_string_value(sym));
239 strip(line);
240
241 switch (line[0]) {
242 case 'n':
243 case 'N':
244 newval = no;
245 if (!line[1] || !strcmp(&line[1], "o"))
246 break;
247 continue;
248 case 'm':
249 case 'M':
250 newval = mod;
251 if (!line[1])
252 break;
253 continue;
254 case 'y':
255 case 'Y':
256 newval = yes;
257 if (!line[1] || !strcmp(&line[1], "es"))
258 break;
259 continue;
260 case 0:
261 newval = oldval;
262 break;
263 case '?':
264 goto help;
265 default:
266 continue;
267 }
268 if (sym_set_tristate_value(sym, newval))
269 return 0;
270help:
271 help = nohelp_text;
272 if (sym->help)
273 help = sym->help;
274 printf("\n%s\n", help);
275 }
276}
277
278static int conf_choice(struct menu *menu)
279{
280 struct symbol *sym, *def_sym;
281 struct menu *child;
282 int type;
283 bool is_new;
284
285 sym = menu->sym;
286 type = sym_get_type(sym);
287 is_new = !sym_has_value(sym);
288 if (sym_is_changable(sym)) {
289 conf_sym(menu);
290 sym_calc_value(sym);
291 switch (sym_get_tristate_value(sym)) {
292 case no:
293 return 1;
294 case mod:
295 return 0;
296 case yes:
297 break;
298 }
299 } else {
300 switch (sym_get_tristate_value(sym)) {
301 case no:
302 return 1;
303 case mod:
304 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
305 return 0;
306 case yes:
307 break;
308 }
309 }
310
311 while (1) {
312 int cnt, def;
313
314 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
315 def_sym = sym_get_choice_value(sym);
316 cnt = def = 0;
317 line[0] = '0';
318 line[1] = 0;
319 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);
359 fgets(line, 128, stdin);
360 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 '?':
535 printf("%s [-o|-s] config\n", av[0]);
536 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)) {
576 conf_read_simple(name);
577 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))
587 conf_read_simple(name);
588 else if (!stat("all.config", &tmpstat))
589 conf_read_simple("all.config");
590 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 }
602 }
603 do {
604 conf_cnt = 0;
605 check_conf(&rootmenu);
606 } while (conf_cnt);
607 if (conf_write(NULL)) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700608 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return 1;
610 }
611 return 0;
612}