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(*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 
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 
80 	if (!sym_is_changable(sym)) {
81 		printf("%s\n", def);
82 		line[0] = '\n';
83 		line[1] = 0;
84 		return;
85 	}
86 
87 	switch (input_mode) {
88 	case set_no:
89 	case set_mod:
90 	case set_yes:
91 	case set_random:
92 		if (sym_has_value(sym)) {
93 			printf("%s\n", def);
94 			return;
95 		}
96 		break;
97 	case ask_new:
98 	case ask_silent:
99 		if (sym_has_value(sym)) {
100 			printf("%s\n", def);
101 			return;
102 		}
103 		check_stdin();
104 	case ask_all:
105 		fflush(stdout);
106 		fgets(line, 128, stdin);
107 		return;
108 	case set_default:
109 		printf("%s\n", def);
110 		return;
111 	default:
112 		break;
113 	}
114 
115 	switch (type) {
116 	case S_INT:
117 	case S_HEX:
118 	case S_STRING:
119 		printf("%s\n", def);
120 		return;
121 	default:
122 		;
123 	}
124 	switch (input_mode) {
125 	case set_yes:
126 		if (sym_tristate_within_range(sym, yes)) {
127 			line[0] = 'y';
128 			line[1] = '\n';
129 			line[2] = 0;
130 			break;
131 		}
132 	case set_mod:
133 		if (type == S_TRISTATE) {
134 			if (sym_tristate_within_range(sym, mod)) {
135 				line[0] = 'm';
136 				line[1] = '\n';
137 				line[2] = 0;
138 				break;
139 			}
140 		} else {
141 			if (sym_tristate_within_range(sym, yes)) {
142 				line[0] = 'y';
143 				line[1] = '\n';
144 				line[2] = 0;
145 				break;
146 			}
147 		}
148 	case set_no:
149 		if (sym_tristate_within_range(sym, no)) {
150 			line[0] = 'n';
151 			line[1] = '\n';
152 			line[2] = 0;
153 			break;
154 		}
155 	case set_random:
156 		do {
157 			val = (tristate)(random() % 3);
158 		} while (!sym_tristate_within_range(sym, val));
159 		switch (val) {
160 		case no: line[0] = 'n'; break;
161 		case mod: line[0] = 'm'; break;
162 		case yes: line[0] = 'y'; break;
163 		}
164 		line[1] = '\n';
165 		line[2] = 0;
166 		break;
167 	default:
168 		break;
169 	}
170 	printf("%s", line);
171 }
172 
conf_string(struct menu * menu)173 int conf_string(struct menu *menu)
174 {
175 	struct symbol *sym = menu->sym;
176 	const char *def;
177 
178 	while (1) {
179 		printf("%*s%s ", indent - 1, "", menu->prompt->text);
180 		printf("(%s) ", sym->name);
181 		def = sym_get_string_value(sym);
182 		if (sym_get_string_value(sym))
183 			printf("[%s] ", def);
184 		conf_askvalue(sym, def);
185 		switch (line[0]) {
186 		case '\n':
187 			break;
188 		case '?':
189 			/* print help */
190 			if (line[1] == '\n') {
191 				printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text);
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 
conf_sym(struct menu * menu)204 static int conf_sym(struct menu *menu)
205 {
206 	struct symbol *sym = menu->sym;
207 	tristate oldval, newval;
208 	const char *help;
209 
210 	while (1) {
211 		printf("%*s%s ", indent - 1, "", menu->prompt->text);
212 		if (sym->name)
213 			printf("(%s) ", sym->name);
214 		putchar('[');
215 		oldval = sym_get_tristate_value(sym);
216 		switch (oldval) {
217 		case no:
218 			putchar('N');
219 			break;
220 		case mod:
221 			putchar('M');
222 			break;
223 		case yes:
224 			putchar('Y');
225 			break;
226 		}
227 		if (oldval != no && sym_tristate_within_range(sym, no))
228 			printf("/n");
229 		if (oldval != mod && sym_tristate_within_range(sym, mod))
230 			printf("/m");
231 		if (oldval != yes && sym_tristate_within_range(sym, yes))
232 			printf("/y");
233 		if (sym->help)
234 			printf("/?");
235 		printf("] ");
236 		conf_askvalue(sym, sym_get_string_value(sym));
237 		strip(line);
238 
239 		switch (line[0]) {
240 		case 'n':
241 		case 'N':
242 			newval = no;
243 			if (!line[1] || !strcmp(&line[1], "o"))
244 				break;
245 			continue;
246 		case 'm':
247 		case 'M':
248 			newval = mod;
249 			if (!line[1])
250 				break;
251 			continue;
252 		case 'y':
253 		case 'Y':
254 			newval = yes;
255 			if (!line[1] || !strcmp(&line[1], "es"))
256 				break;
257 			continue;
258 		case 0:
259 			newval = oldval;
260 			break;
261 		case '?':
262 			goto help;
263 		default:
264 			continue;
265 		}
266 		if (sym_set_tristate_value(sym, newval))
267 			return 0;
268 help:
269 		help = nohelp_text;
270 		if (sym->help)
271 			help = sym->help;
272 		printf("\n%s\n", help);
273 	}
274 }
275 
conf_choice(struct menu * menu)276 static int conf_choice(struct menu *menu)
277 {
278 	struct symbol *sym, *def_sym;
279 	struct menu *child;
280 	bool is_new;
281 
282 	sym = menu->sym;
283 	is_new = !sym_has_value(sym);
284 	if (sym_is_changable(sym)) {
285 		conf_sym(menu);
286 		sym_calc_value(sym);
287 		switch (sym_get_tristate_value(sym)) {
288 		case no:
289 			return 1;
290 		case mod:
291 			return 0;
292 		case yes:
293 			break;
294 		}
295 	} else {
296 		switch (sym_get_tristate_value(sym)) {
297 		case no:
298 			return 1;
299 		case mod:
300 			printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
301 			return 0;
302 		case yes:
303 			break;
304 		}
305 	}
306 
307 	while (1) {
308 		int cnt, def;
309 
310 		printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
311 		def_sym = sym_get_choice_value(sym);
312 		cnt = def = 0;
313 		line[0] = 0;
314 		for (child = menu->list; child; child = child->next) {
315 			if (!menu_is_visible(child))
316 				continue;
317 			if (!child->sym) {
318 				printf("%*c %s\n", indent, '*', menu_get_prompt(child));
319 				continue;
320 			}
321 			cnt++;
322 			if (child->sym == def_sym) {
323 				def = cnt;
324 				printf("%*c", indent, '>');
325 			} else
326 				printf("%*c", indent, ' ');
327 			printf(" %d. %s", cnt, menu_get_prompt(child));
328 			if (child->sym->name)
329 				printf(" (%s)", child->sym->name);
330 			if (!sym_has_value(child->sym))
331 				printf(" (NEW)");
332 			printf("\n");
333 		}
334 		printf("%*schoice", indent - 1, "");
335 		if (cnt == 1) {
336 			printf("[1]: 1\n");
337 			goto conf_childs;
338 		}
339 		printf("[1-%d", cnt);
340 		if (sym->help)
341 			printf("?");
342 		printf("]: ");
343 		switch (input_mode) {
344 		case ask_new:
345 		case ask_silent:
346 			if (!is_new) {
347 				cnt = def;
348 				printf("%d\n", cnt);
349 				break;
350 			}
351 			check_stdin();
352 		case ask_all:
353 			fflush(stdout);
354 			fgets(line, 128, stdin);
355 			strip(line);
356 			if (line[0] == '?') {
357 				printf("\n%s\n", menu->sym->help ?
358 					menu->sym->help : nohelp_text);
359 				continue;
360 			}
361 			if (!line[0])
362 				cnt = def;
363 			else if (isdigit(line[0]))
364 				cnt = atoi(line);
365 			else
366 				continue;
367 			break;
368 		case set_random:
369 			def = (random() % cnt) + 1;
370 		case set_default:
371 		case set_yes:
372 		case set_mod:
373 		case set_no:
374 			cnt = def;
375 			printf("%d\n", cnt);
376 			break;
377 		}
378 
379 	conf_childs:
380 		for (child = menu->list; child; child = child->next) {
381 			if (!child->sym || !menu_is_visible(child))
382 				continue;
383 			if (!--cnt)
384 				break;
385 		}
386 		if (!child)
387 			continue;
388 		if (strlen(line) > 0 && line[strlen(line) - 1] == '?') {
389 			printf("\n%s\n", child->sym->help ?
390 				child->sym->help : nohelp_text);
391 			continue;
392 		}
393 		sym_set_choice_value(sym, child->sym);
394 		if (child->list) {
395 			indent += 2;
396 			conf(child->list);
397 			indent -= 2;
398 		}
399 		return 1;
400 	}
401 }
402 
conf(struct menu * menu)403 static void conf(struct menu *menu)
404 {
405 	struct symbol *sym;
406 	struct property *prop;
407 	struct menu *child;
408 
409 	if (!menu_is_visible(menu))
410 		return;
411 
412 	sym = menu->sym;
413 	prop = menu->prompt;
414 	if (prop) {
415 		const char *prompt;
416 
417 		switch (prop->type) {
418 		case P_MENU:
419 			if (input_mode == ask_silent && rootEntry != menu) {
420 				check_conf(menu);
421 				return;
422 			}
423 		case P_COMMENT:
424 			prompt = menu_get_prompt(menu);
425 			if (prompt)
426 				printf("%*c\n%*c %s\n%*c\n",
427 					indent, '*',
428 					indent, '*', prompt,
429 					indent, '*');
430 		default:
431 			;
432 		}
433 	}
434 
435 	if (!sym)
436 		goto conf_childs;
437 
438 	if (sym_is_choice(sym)) {
439 		conf_choice(menu);
440 		if (sym->curr.tri != mod)
441 			return;
442 		goto conf_childs;
443 	}
444 
445 	switch (sym->type) {
446 	case S_INT:
447 	case S_HEX:
448 	case S_STRING:
449 		conf_string(menu);
450 		break;
451 	default:
452 		conf_sym(menu);
453 		break;
454 	}
455 
456 conf_childs:
457 	if (sym)
458 		indent += 2;
459 	for (child = menu->list; child; child = child->next)
460 		conf(child);
461 	if (sym)
462 		indent -= 2;
463 }
464 
check_conf(struct menu * menu)465 static void check_conf(struct menu *menu)
466 {
467 	struct symbol *sym;
468 	struct menu *child;
469 
470 	if (!menu_is_visible(menu))
471 		return;
472 
473 	sym = menu->sym;
474 	if (sym && !sym_has_value(sym)) {
475 		if (sym_is_changable(sym) ||
476 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
477 			if (!conf_cnt++)
478 				printf(_("*\n* Restart config...\n*\n"));
479 			rootEntry = menu_get_parent_menu(menu);
480 			conf(rootEntry);
481 		}
482 	}
483 
484 	for (child = menu->list; child; child = child->next)
485 		check_conf(child);
486 }
487 
main(int ac,char ** av)488 int main(int ac, char **av)
489 {
490 	int i = 1;
491 	const char *name;
492 	struct stat tmpstat;
493 
494 	if (ac > i && av[i][0] == '-') {
495 		switch (av[i++][1]) {
496 		case 'o':
497 			input_mode = ask_new;
498 			break;
499 		case 's':
500 			input_mode = ask_silent;
501 			valid_stdin = isatty(0); //bbox: && isatty(1) && isatty(2);
502 			break;
503 		case 'd':
504 			input_mode = set_default;
505 			break;
506 		case 'D':
507 			input_mode = set_default;
508 			defconfig_file = av[i++];
509 			if (!defconfig_file) {
510 				printf(_("%s: No default config file specified\n"),
511 					av[0]);
512 				exit(1);
513 			}
514 			break;
515 		case 'n':
516 			input_mode = set_no;
517 			break;
518 		case 'm':
519 			input_mode = set_mod;
520 			break;
521 		case 'y':
522 			input_mode = set_yes;
523 			break;
524 		case 'r':
525 			input_mode = set_random;
526 			srandom(time(NULL));
527 			break;
528 		case 'h':
529 		case '?':
530 			fprintf(stderr, "See README for usage info\n");
531 			exit(0);
532 		}
533 	}
534 	name = av[i];
535 	if (!name) {
536 		printf(_("%s: Kconfig file missing\n"), av[0]);
537 	}
538 	conf_parse(name);
539 	//zconfdump(stdout);
540 	switch (input_mode) {
541 	case set_default:
542 		if (!defconfig_file)
543 			defconfig_file = conf_get_default_confname();
544 		if (conf_read(defconfig_file)) {
545 			printf("***\n"
546 				"*** Can't find default configuration \"%s\"!\n"
547 				"***\n", defconfig_file);
548 			exit(1);
549 		}
550 		break;
551 	case ask_silent:
552 		if (stat(".config", &tmpstat)) {
553 			printf(_("***\n"
554 				"*** You have not yet configured busybox!\n"
555 				"***\n"
556 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
557 				"*** \"make menuconfig\" or \"make defconfig\").\n"
558 				"***\n"));
559 			exit(1);
560 		}
561 	case ask_all:
562 	case ask_new:
563 		conf_read(NULL);
564 		break;
565 	case set_no:
566 	case set_mod:
567 	case set_yes:
568 	case set_random:
569 		name = getenv("KCONFIG_ALLCONFIG");
570 		if (name && !stat(name, &tmpstat)) {
571 			conf_read_simple(name);
572 			break;
573 		}
574 		switch (input_mode) {
575 		case set_no:	 name = "allno.config"; break;
576 		case set_mod:	 name = "allmod.config"; break;
577 		case set_yes:	 name = "allyes.config"; break;
578 		case set_random: name = "allrandom.config"; break;
579 		default: break;
580 		}
581 		if (!stat(name, &tmpstat))
582 			conf_read_simple(name);
583 		else if (!stat("all.config", &tmpstat))
584 			conf_read_simple("all.config");
585 		break;
586 	default:
587 		break;
588 	}
589 
590 	if (input_mode != ask_silent) {
591 		rootEntry = &rootmenu;
592 		conf(&rootmenu);
593 		if (input_mode == ask_all) {
594 			input_mode = ask_silent;
595 			valid_stdin = 1;
596 		}
597 	}
598 	do {
599 		conf_cnt = 0;
600 		check_conf(&rootmenu);
601 	} while (conf_cnt);
602 	if (conf_write(NULL)) {
603 		fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
604 		return 1;
605 	}
606 	return 0;
607 }
608