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