blob: 866a7c544de53b08c3bc607172d2fa162c0a3918 [file] [log] [blame]
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001/*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 */
5
Denys Vlasenkob83c9702011-04-18 01:19:59 +02006#define _XOPEN_SOURCE 700
7
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00008#include <ctype.h>
9#include <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12#include <unistd.h>
13#include <time.h>
14#include <sys/stat.h>
15
16#define LKC_DIRECT_LINK
17#include "lkc.h"
18
19static void conf(struct menu *menu);
20static void check_conf(struct menu *menu);
21
22enum {
23 ask_all,
24 ask_new,
25 ask_silent,
26 set_default,
27 set_yes,
28 set_mod,
29 set_no,
30 set_random
31} input_mode = ask_all;
32char *defconfig_file;
33
34static int indent = 1;
35static int valid_stdin = 1;
36static int conf_cnt;
37static char line[128];
38static struct menu *rootEntry;
39
40static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
41
42static void strip(char *str)
43{
44 char *p = str;
45 int l;
46
47 while ((isspace(*p)))
48 p++;
49 l = strlen(p);
50 if (p != str)
51 memmove(str, p, l + 1);
52 if (!l)
53 return;
54 p = str + l - 1;
55 while ((isspace(*p)))
56 *p-- = 0;
57}
58
59static void check_stdin(void)
60{
61 if (!valid_stdin && input_mode == ask_silent) {
62 printf(_("aborted!\n\n"));
63 printf(_("Console input/output is redirected. "));
64 printf(_("Run 'make oldconfig' to update configuration.\n\n"));
65 exit(1);
66 }
67}
68
69static void conf_askvalue(struct symbol *sym, const char *def)
70{
71 enum symbol_type type = sym_get_type(sym);
72 tristate val;
73
74 if (!sym_has_value(sym))
75 printf("(NEW) ");
76
77 line[0] = '\n';
78 line[1] = 0;
Denys Vlasenko0b1c6292017-09-07 14:40:28 +020079 line[2] = 0;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000080
81 if (!sym_is_changable(sym)) {
82 printf("%s\n", def);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000083 return;
84 }
85
Denys Vlasenko0b1c6292017-09-07 14:40:28 +020086 // If autoconf run (allnoconfig and such), reset bool and tristates:
87 // "select ITEM" sets ITEM=y and then parent item might have been
88 // reset to "n" later. Try to set ITEM to "n" on the second run.
89 if (type == S_BOOLEAN || type == S_TRISTATE) {
90 switch (input_mode) {
91 case set_yes:
92 if (sym_tristate_within_range(sym, yes)) {
93 line[0] = 'y';
94 line[1] = '\n';
95 printf("%s", line);
96 return;
97 }
98 case set_mod:
99 if (type == S_TRISTATE) {
100 if (sym_tristate_within_range(sym, mod)) {
101 line[0] = 'm';
102 line[1] = '\n';
103 printf("%s", line);
104 return;
105 }
106 } else {
107 if (sym_tristate_within_range(sym, yes)) {
108 line[0] = 'y';
109 line[1] = '\n';
110 printf("%s", line);
111 return;
112 }
113 }
114 case set_no:
115 if (sym_tristate_within_range(sym, no)) {
116 line[0] = 'n';
117 line[1] = '\n';
118 printf("%s", line);
119 return;
120 }
Denys Vlasenkod134aa92017-09-07 14:50:00 +0200121 default: // placate compiler
122 break;
Denys Vlasenko0b1c6292017-09-07 14:40:28 +0200123 }
124 }
125
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000126 switch (input_mode) {
127 case set_no:
128 case set_mod:
129 case set_yes:
130 case set_random:
131 if (sym_has_value(sym)) {
132 printf("%s\n", def);
133 return;
134 }
135 break;
136 case ask_new:
137 case ask_silent:
138 if (sym_has_value(sym)) {
139 printf("%s\n", def);
140 return;
141 }
142 check_stdin();
143 case ask_all:
144 fflush(stdout);
Denys Vlasenko4bdc9142019-01-06 20:12:16 +0100145 if (!fgets(line, 128, stdin))
146 exit(1);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000147 return;
148 case set_default:
149 printf("%s\n", def);
150 return;
151 default:
152 break;
153 }
154
155 switch (type) {
156 case S_INT:
157 case S_HEX:
158 case S_STRING:
159 printf("%s\n", def);
160 return;
161 default:
162 ;
163 }
164 switch (input_mode) {
165 case set_yes:
166 if (sym_tristate_within_range(sym, yes)) {
167 line[0] = 'y';
168 line[1] = '\n';
169 line[2] = 0;
170 break;
171 }
172 case set_mod:
173 if (type == S_TRISTATE) {
174 if (sym_tristate_within_range(sym, mod)) {
175 line[0] = 'm';
176 line[1] = '\n';
177 line[2] = 0;
178 break;
179 }
180 } else {
181 if (sym_tristate_within_range(sym, yes)) {
182 line[0] = 'y';
183 line[1] = '\n';
184 line[2] = 0;
185 break;
186 }
187 }
188 case set_no:
189 if (sym_tristate_within_range(sym, no)) {
190 line[0] = 'n';
191 line[1] = '\n';
192 line[2] = 0;
193 break;
194 }
195 case set_random:
196 do {
197 val = (tristate)(random() % 3);
198 } while (!sym_tristate_within_range(sym, val));
199 switch (val) {
200 case no: line[0] = 'n'; break;
201 case mod: line[0] = 'm'; break;
202 case yes: line[0] = 'y'; break;
203 }
204 line[1] = '\n';
205 line[2] = 0;
206 break;
207 default:
208 break;
209 }
210 printf("%s", line);
211}
212
213int conf_string(struct menu *menu)
214{
215 struct symbol *sym = menu->sym;
Cristian Ionescu-Idbohrnfcbc6412011-05-01 14:43:53 +0200216 const char *def;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000217
218 while (1) {
219 printf("%*s%s ", indent - 1, "", menu->prompt->text);
220 printf("(%s) ", sym->name);
221 def = sym_get_string_value(sym);
222 if (sym_get_string_value(sym))
223 printf("[%s] ", def);
224 conf_askvalue(sym, def);
225 switch (line[0]) {
226 case '\n':
227 break;
228 case '?':
229 /* print help */
230 if (line[1] == '\n') {
Cristian Ionescu-Idbohrnfcbc6412011-05-01 14:43:53 +0200231 printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000232 def = NULL;
233 break;
234 }
235 default:
236 line[strlen(line)-1] = 0;
237 def = line;
238 }
239 if (def && sym_set_string_value(sym, def))
240 return 0;
241 }
242}
243
244static int conf_sym(struct menu *menu)
245{
246 struct symbol *sym = menu->sym;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000247 tristate oldval, newval;
248 const char *help;
249
250 while (1) {
251 printf("%*s%s ", indent - 1, "", menu->prompt->text);
252 if (sym->name)
253 printf("(%s) ", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000254 putchar('[');
255 oldval = sym_get_tristate_value(sym);
256 switch (oldval) {
257 case no:
258 putchar('N');
259 break;
260 case mod:
261 putchar('M');
262 break;
263 case yes:
264 putchar('Y');
265 break;
266 }
267 if (oldval != no && sym_tristate_within_range(sym, no))
268 printf("/n");
269 if (oldval != mod && sym_tristate_within_range(sym, mod))
270 printf("/m");
271 if (oldval != yes && sym_tristate_within_range(sym, yes))
272 printf("/y");
273 if (sym->help)
274 printf("/?");
275 printf("] ");
276 conf_askvalue(sym, sym_get_string_value(sym));
277 strip(line);
278
279 switch (line[0]) {
280 case 'n':
281 case 'N':
282 newval = no;
283 if (!line[1] || !strcmp(&line[1], "o"))
284 break;
285 continue;
286 case 'm':
287 case 'M':
288 newval = mod;
289 if (!line[1])
290 break;
291 continue;
292 case 'y':
293 case 'Y':
294 newval = yes;
295 if (!line[1] || !strcmp(&line[1], "es"))
296 break;
297 continue;
298 case 0:
299 newval = oldval;
300 break;
301 case '?':
302 goto help;
303 default:
304 continue;
305 }
306 if (sym_set_tristate_value(sym, newval))
307 return 0;
308help:
309 help = nohelp_text;
310 if (sym->help)
311 help = sym->help;
312 printf("\n%s\n", help);
313 }
314}
315
316static int conf_choice(struct menu *menu)
317{
318 struct symbol *sym, *def_sym;
319 struct menu *child;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000320 bool is_new;
321
322 sym = menu->sym;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000323 is_new = !sym_has_value(sym);
324 if (sym_is_changable(sym)) {
325 conf_sym(menu);
326 sym_calc_value(sym);
327 switch (sym_get_tristate_value(sym)) {
328 case no:
329 return 1;
330 case mod:
331 return 0;
332 case yes:
333 break;
334 }
335 } else {
336 switch (sym_get_tristate_value(sym)) {
337 case no:
338 return 1;
339 case mod:
340 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
341 return 0;
342 case yes:
343 break;
344 }
345 }
346
347 while (1) {
348 int cnt, def;
349
350 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
351 def_sym = sym_get_choice_value(sym);
352 cnt = def = 0;
353 line[0] = 0;
354 for (child = menu->list; child; child = child->next) {
355 if (!menu_is_visible(child))
356 continue;
357 if (!child->sym) {
358 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
359 continue;
360 }
361 cnt++;
362 if (child->sym == def_sym) {
363 def = cnt;
364 printf("%*c", indent, '>');
365 } else
366 printf("%*c", indent, ' ');
367 printf(" %d. %s", cnt, menu_get_prompt(child));
368 if (child->sym->name)
369 printf(" (%s)", child->sym->name);
370 if (!sym_has_value(child->sym))
371 printf(" (NEW)");
372 printf("\n");
373 }
374 printf("%*schoice", indent - 1, "");
375 if (cnt == 1) {
376 printf("[1]: 1\n");
377 goto conf_childs;
378 }
379 printf("[1-%d", cnt);
380 if (sym->help)
381 printf("?");
382 printf("]: ");
383 switch (input_mode) {
384 case ask_new:
385 case ask_silent:
386 if (!is_new) {
387 cnt = def;
388 printf("%d\n", cnt);
389 break;
390 }
391 check_stdin();
392 case ask_all:
393 fflush(stdout);
Denys Vlasenko4bdc9142019-01-06 20:12:16 +0100394 if (!fgets(line, 128, stdin))
395 exit(1);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000396 strip(line);
397 if (line[0] == '?') {
398 printf("\n%s\n", menu->sym->help ?
399 menu->sym->help : nohelp_text);
400 continue;
401 }
402 if (!line[0])
403 cnt = def;
404 else if (isdigit(line[0]))
405 cnt = atoi(line);
406 else
407 continue;
408 break;
409 case set_random:
410 def = (random() % cnt) + 1;
411 case set_default:
412 case set_yes:
413 case set_mod:
414 case set_no:
415 cnt = def;
416 printf("%d\n", cnt);
417 break;
418 }
419
420 conf_childs:
421 for (child = menu->list; child; child = child->next) {
422 if (!child->sym || !menu_is_visible(child))
423 continue;
424 if (!--cnt)
425 break;
426 }
427 if (!child)
428 continue;
Mike Frysinger40ae9b52006-12-30 19:30:20 +0000429 if (strlen(line) > 0 && line[strlen(line) - 1] == '?') {
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000430 printf("\n%s\n", child->sym->help ?
431 child->sym->help : nohelp_text);
432 continue;
433 }
434 sym_set_choice_value(sym, child->sym);
435 if (child->list) {
436 indent += 2;
437 conf(child->list);
438 indent -= 2;
439 }
440 return 1;
441 }
442}
443
444static void conf(struct menu *menu)
445{
446 struct symbol *sym;
447 struct property *prop;
448 struct menu *child;
449
450 if (!menu_is_visible(menu))
451 return;
452
453 sym = menu->sym;
454 prop = menu->prompt;
455 if (prop) {
456 const char *prompt;
457
458 switch (prop->type) {
459 case P_MENU:
460 if (input_mode == ask_silent && rootEntry != menu) {
461 check_conf(menu);
462 return;
463 }
464 case P_COMMENT:
465 prompt = menu_get_prompt(menu);
466 if (prompt)
467 printf("%*c\n%*c %s\n%*c\n",
468 indent, '*',
469 indent, '*', prompt,
470 indent, '*');
471 default:
472 ;
473 }
474 }
475
476 if (!sym)
477 goto conf_childs;
478
479 if (sym_is_choice(sym)) {
480 conf_choice(menu);
481 if (sym->curr.tri != mod)
482 return;
483 goto conf_childs;
484 }
485
486 switch (sym->type) {
487 case S_INT:
488 case S_HEX:
489 case S_STRING:
490 conf_string(menu);
491 break;
492 default:
493 conf_sym(menu);
494 break;
495 }
496
497conf_childs:
498 if (sym)
499 indent += 2;
500 for (child = menu->list; child; child = child->next)
501 conf(child);
502 if (sym)
503 indent -= 2;
504}
505
506static void check_conf(struct menu *menu)
507{
508 struct symbol *sym;
509 struct menu *child;
510
511 if (!menu_is_visible(menu))
512 return;
513
514 sym = menu->sym;
515 if (sym && !sym_has_value(sym)) {
516 if (sym_is_changable(sym) ||
517 (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
518 if (!conf_cnt++)
519 printf(_("*\n* Restart config...\n*\n"));
520 rootEntry = menu_get_parent_menu(menu);
521 conf(rootEntry);
522 }
523 }
524
525 for (child = menu->list; child; child = child->next)
526 check_conf(child);
527}
528
529int main(int ac, char **av)
530{
531 int i = 1;
532 const char *name;
533 struct stat tmpstat;
534
535 if (ac > i && av[i][0] == '-') {
536 switch (av[i++][1]) {
537 case 'o':
538 input_mode = ask_new;
539 break;
540 case 's':
541 input_mode = ask_silent;
Denis Vlasenkodbcf3272008-06-28 04:00:01 +0000542 valid_stdin = isatty(0); //bbox: && isatty(1) && isatty(2);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000543 break;
544 case 'd':
545 input_mode = set_default;
546 break;
547 case 'D':
548 input_mode = set_default;
549 defconfig_file = av[i++];
550 if (!defconfig_file) {
551 printf(_("%s: No default config file specified\n"),
552 av[0]);
553 exit(1);
554 }
555 break;
556 case 'n':
557 input_mode = set_no;
558 break;
559 case 'm':
560 input_mode = set_mod;
561 break;
562 case 'y':
563 input_mode = set_yes;
564 break;
565 case 'r':
566 input_mode = set_random;
567 srandom(time(NULL));
568 break;
569 case 'h':
570 case '?':
571 fprintf(stderr, "See README for usage info\n");
572 exit(0);
573 }
574 }
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000575 name = av[i];
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000576 if (!name) {
577 printf(_("%s: Kconfig file missing\n"), av[0]);
578 }
579 conf_parse(name);
580 //zconfdump(stdout);
581 switch (input_mode) {
582 case set_default:
583 if (!defconfig_file)
584 defconfig_file = conf_get_default_confname();
585 if (conf_read(defconfig_file)) {
586 printf("***\n"
587 "*** Can't find default configuration \"%s\"!\n"
588 "***\n", defconfig_file);
589 exit(1);
590 }
591 break;
592 case ask_silent:
593 if (stat(".config", &tmpstat)) {
594 printf(_("***\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000595 "*** You have not yet configured busybox!\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000596 "***\n"
597 "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000598 "*** \"make menuconfig\" or \"make defconfig\").\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000599 "***\n"));
600 exit(1);
601 }
602 case ask_all:
603 case ask_new:
604 conf_read(NULL);
605 break;
606 case set_no:
607 case set_mod:
608 case set_yes:
609 case set_random:
610 name = getenv("KCONFIG_ALLCONFIG");
611 if (name && !stat(name, &tmpstat)) {
612 conf_read_simple(name);
613 break;
614 }
615 switch (input_mode) {
616 case set_no: name = "allno.config"; break;
617 case set_mod: name = "allmod.config"; break;
618 case set_yes: name = "allyes.config"; break;
619 case set_random: name = "allrandom.config"; break;
620 default: break;
621 }
622 if (!stat(name, &tmpstat))
623 conf_read_simple(name);
624 else if (!stat("all.config", &tmpstat))
625 conf_read_simple("all.config");
626 break;
627 default:
628 break;
629 }
630
631 if (input_mode != ask_silent) {
632 rootEntry = &rootmenu;
633 conf(&rootmenu);
Denys Vlasenko0b1c6292017-09-07 14:40:28 +0200634 // If autoconf run (allnoconfig and such), run it twice:
635 // "select ITEM" sets ITEM=y and then parent item
636 // is reset to "n" later. Second run sets ITEM to "n".
637 // Example: ADDUSER selects LONG_OPTS.
638 // allnoconfig must set _both_ to "n".
639 // Before, LONG_OPTS remained "y".
640 if (input_mode == set_no
641 || input_mode == set_mod
642 || input_mode == set_yes
643 ) {
644 rootEntry = &rootmenu;
645 conf(&rootmenu);
646 }
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000647 if (input_mode == ask_all) {
648 input_mode = ask_silent;
649 valid_stdin = 1;
650 }
651 }
652 do {
653 conf_cnt = 0;
654 check_conf(&rootmenu);
655 } while (conf_cnt);
656 if (conf_write(NULL)) {
Denis Vlasenko417e2402008-05-28 11:59:32 +0000657 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000658 return 1;
659 }
660 return 0;
661}