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 #define _XOPEN_SOURCE 700
7
8 #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
19 static void conf(struct menu *menu);
20 static void check_conf(struct menu *menu);
21
22 enum {
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;
32 char *defconfig_file;
33
34 static int indent = 1;
35 static int valid_stdin = 1;
36 static int conf_cnt;
37 static char line[128];
38 static struct menu *rootEntry;
39
40 static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
41
strip(char * str)42 static void strip(char *str)
43 {
44 char *p = str;
45 int l;
46
47 while ((isspace((unsigned char)*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((unsigned char)*p)))
56 *p-- = 0;
57 }
58
check_stdin(void)59 static 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
conf_askvalue(struct symbol * sym,const char * def)69 static 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;
79 line[2] = 0;
80
81 if (!sym_is_changable(sym)) {
82 printf("%s\n", def);
83 return;
84 }
85
86 // 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 }
121 default: // placate compiler
122 break;
123 }
124 }
125
126 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);
145 if (!fgets(line, 128, stdin))
146 exit(1);
147 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
conf_string(struct menu * menu)213 int conf_string(struct menu *menu)
214 {
215 struct symbol *sym = menu->sym;
216 const char *def;
217
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') {
231 printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text);
232 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
conf_sym(struct menu * menu)244 static int conf_sym(struct menu *menu)
245 {
246 struct symbol *sym = menu->sym;
247 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);
254 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;
308 help:
309 help = nohelp_text;
310 if (sym->help)
311 help = sym->help;
312 printf("\n%s\n", help);
313 }
314 }
315
conf_choice(struct menu * menu)316 static int conf_choice(struct menu *menu)
317 {
318 struct symbol *sym, *def_sym;
319 struct menu *child;
320 bool is_new;
321
322 sym = menu->sym;
323 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);
394 if (!fgets(line, 128, stdin))
395 exit(1);
396 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((unsigned char)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;
429 if (strlen(line) > 0 && line[strlen(line) - 1] == '?') {
430 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
conf(struct menu * menu)444 static 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
497 conf_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
check_conf(struct menu * menu)506 static 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
main(int ac,char ** av)529 int 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;
542 valid_stdin = isatty(0); //bbox: && isatty(1) && isatty(2);
543 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 }
575 name = av[i];
576 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"
595 "*** You have not yet configured busybox!\n"
596 "***\n"
597 "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
598 "*** \"make menuconfig\" or \"make defconfig\").\n"
599 "***\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);
634 // 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 }
647 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)) {
657 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
658 return 1;
659 }
660 return 0;
661 }
662