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 #include <ctype.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <time.h>
12 #include <sys/stat.h>
13 
14 #define LKC_DIRECT_LINK
15 #include "lkc.h"
16 
17 static void conf(struct menu *menu);
18 static void check_conf(struct menu *menu);
19 
20 enum {
21 	ask_all,
22 	ask_new,
23 	ask_silent,
24 	set_default,
25 	set_yes,
26 	set_mod,
27 	set_no,
28 	set_random
29 } input_mode = ask_all;
30 char *defconfig_file;
31 
32 static int indent = 1;
33 static int valid_stdin = 1;
34 static int conf_cnt;
35 static char line[128];
36 static struct menu *rootEntry;
37 
38 static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
39 
strip(char * str)40 static void strip(char *str)
41 {
42 	char *p = str;
43 	int l;
44 
45 	while ((isspace(*p)))
46 		p++;
47 	l = strlen(p);
48 	if (p != str)
49 		memmove(str, p, l + 1);
50 	if (!l)
51 		return;
52 	p = str + l - 1;
53 	while ((isspace(*p)))
54 		*p-- = 0;
55 }
56 
check_stdin(void)57 static void check_stdin(void)
58 {
59 	if (!valid_stdin && input_mode == ask_silent) {
60 		printf(_("aborted!\n\n"));
61 		printf(_("Console input/output is redirected. "));
62 		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
63 		exit(1);
64 	}
65 }
66 
conf_askvalue(struct symbol * sym,const char * def)67 static void conf_askvalue(struct symbol *sym, const char *def)
68 {
69 	enum symbol_type type = sym_get_type(sym);
70 	tristate val;
71 
72 	if (!sym_has_value(sym))
73 		printf("(NEW) ");
74 
75 	line[0] = '\n';
76 	line[1] = 0;
77 
78 	if (!sym_is_changable(sym)) {
79 		printf("%s\n", def);
80 		line[0] = '\n';
81 		line[1] = 0;
82 		return;
83 	}
84 
85 	switch (input_mode) {
86 	case set_no:
87 	case set_mod:
88 	case set_yes:
89 	case set_random:
90 		if (sym_has_value(sym)) {
91 			printf("%s\n", def);
92 			return;
93 		}
94 		break;
95 	case ask_new:
96 	case ask_silent:
97 		if (sym_has_value(sym)) {
98 			printf("%s\n", def);
99 			return;
100 		}
101 		check_stdin();
102 	case ask_all:
103 		fflush(stdout);
104 		fgets(line, 128, stdin);
105 		return;
106 	case set_default:
107 		printf("%s\n", def);
108 		return;
109 	default:
110 		break;
111 	}
112 
113 	switch (type) {
114 	case S_INT:
115 	case S_HEX:
116 	case S_STRING:
117 		printf("%s\n", def);
118 		return;
119 	default:
120 		;
121 	}
122 	switch (input_mode) {
123 	case set_yes:
124 		if (sym_tristate_within_range(sym, yes)) {
125 			line[0] = 'y';
126 			line[1] = '\n';
127 			line[2] = 0;
128 			break;
129 		}
130 	case set_mod:
131 		if (type == S_TRISTATE) {
132 			if (sym_tristate_within_range(sym, mod)) {
133 				line[0] = 'm';
134 				line[1] = '\n';
135 				line[2] = 0;
136 				break;
137 			}
138 		} else {
139 			if (sym_tristate_within_range(sym, yes)) {
140 				line[0] = 'y';
141 				line[1] = '\n';
142 				line[2] = 0;
143 				break;
144 			}
145 		}
146 	case set_no:
147 		if (sym_tristate_within_range(sym, no)) {
148 			line[0] = 'n';
149 			line[1] = '\n';
150 			line[2] = 0;
151 			break;
152 		}
153 	case set_random:
154 		do {
155 			val = (tristate)(random() % 3);
156 		} while (!sym_tristate_within_range(sym, val));
157 		switch (val) {
158 		case no: line[0] = 'n'; break;
159 		case mod: line[0] = 'm'; break;
160 		case yes: line[0] = 'y'; break;
161 		}
162 		line[1] = '\n';
163 		line[2] = 0;
164 		break;
165 	default:
166 		break;
167 	}
168 	printf("%s", line);
169 }
170 
conf_string(struct menu * menu)171 int conf_string(struct menu *menu)
172 {
173 	struct symbol *sym = menu->sym;
174 	const char *def, *help;
175 
176 	while (1) {
177 		printf("%*s%s ", indent - 1, "", menu->prompt->text);
178 		printf("(%s) ", sym->name);
179 		def = sym_get_string_value(sym);
180 		if (sym_get_string_value(sym))
181 			printf("[%s] ", def);
182 		conf_askvalue(sym, def);
183 		switch (line[0]) {
184 		case '\n':
185 			break;
186 		case '?':
187 			/* print help */
188 			if (line[1] == '\n') {
189 				help = nohelp_text;
190 				if (menu->sym->help)
191 					help = menu->sym->help;
192 				printf("\n%s\n", menu->sym->help);
193 				def = NULL;
194 				break;
195 			}
196 		default:
197 			line[strlen(line)-1] = 0;
198 			def = line;
199 		}
200 		if (def && sym_set_string_value(sym, def))
201 			return 0;
202 	}
203 }
204 
conf_sym(struct menu * menu)205 static int conf_sym(struct menu *menu)
206 {
207 	struct symbol *sym = menu->sym;
208 	int type;
209 	tristate oldval, newval;
210 	const char *help;
211 
212 	while (1) {
213 		printf("%*s%s ", indent - 1, "", menu->prompt->text);
214 		if (sym->name)
215 			printf("(%s) ", sym->name);
216 		type = sym_get_type(sym);
217 		putchar('[');
218 		oldval = sym_get_tristate_value(sym);
219 		switch (oldval) {
220 		case no:
221 			putchar('N');
222 			break;
223 		case mod:
224 			putchar('M');
225 			break;
226 		case yes:
227 			putchar('Y');
228 			break;
229 		}
230 		if (oldval != no && sym_tristate_within_range(sym, no))
231 			printf("/n");
232 		if (oldval != mod && sym_tristate_within_range(sym, mod))
233 			printf("/m");
234 		if (oldval != yes && sym_tristate_within_range(sym, yes))
235 			printf("/y");
236 		if (sym->help)
237 			printf("/?");
238 		printf("] ");
239 		conf_askvalue(sym, sym_get_string_value(sym));
240 		strip(line);
241 
242 		switch (line[0]) {
243 		case 'n':
244 		case 'N':
245 			newval = no;
246 			if (!line[1] || !strcmp(&line[1], "o"))
247 				break;
248 			continue;
249 		case 'm':
250 		case 'M':
251 			newval = mod;
252 			if (!line[1])
253 				break;
254 			continue;
255 		case 'y':
256 		case 'Y':
257 			newval = yes;
258 			if (!line[1] || !strcmp(&line[1], "es"))
259 				break;
260 			continue;
261 		case 0:
262 			newval = oldval;
263 			break;
264 		case '?':
265 			goto help;
266 		default:
267 			continue;
268 		}
269 		if (sym_set_tristate_value(sym, newval))
270 			return 0;
271 help:
272 		help = nohelp_text;
273 		if (sym->help)
274 			help = sym->help;
275 		printf("\n%s\n", help);
276 	}
277 }
278 
conf_choice(struct menu * menu)279 static int conf_choice(struct menu *menu)
280 {
281 	struct symbol *sym, *def_sym;
282 	struct menu *child;
283 	int type;
284 	bool is_new;
285 
286 	sym = menu->sym;
287 	type = sym_get_type(sym);
288 	is_new = !sym_has_value(sym);
289 	if (sym_is_changable(sym)) {
290 		conf_sym(menu);
291 		sym_calc_value(sym);
292 		switch (sym_get_tristate_value(sym)) {
293 		case no:
294 			return 1;
295 		case mod:
296 			return 0;
297 		case yes:
298 			break;
299 		}
300 	} else {
301 		switch (sym_get_tristate_value(sym)) {
302 		case no:
303 			return 1;
304 		case mod:
305 			printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
306 			return 0;
307 		case yes:
308 			break;
309 		}
310 	}
311 
312 	while (1) {
313 		int cnt, def;
314 
315 		printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
316 		def_sym = sym_get_choice_value(sym);
317 		cnt = def = 0;
318 		line[0] = 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 
conf(struct menu * menu)408 static 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 
461 conf_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 
check_conf(struct menu * menu)470 static 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;
479 	if (sym && !sym_has_value(sym)) {
480 		if (sym_is_changable(sym) ||
481 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
482 			if (!conf_cnt++)
483 				printf(_("*\n* Restart config...\n*\n"));
484 			rootEntry = menu_get_parent_menu(menu);
485 			conf(rootEntry);
486 		}
487 	}
488 
489 	for (child = menu->list; child; child = child->next)
490 		check_conf(child);
491 }
492 
main(int ac,char ** av)493 int 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) {
515 				printf(_("%s: No default config file specified\n"),
516 					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 			fprintf(stderr, "See README for usage info\n");
536 			exit(0);
537 		}
538 	}
539   	name = av[i];
540 	if (!name) {
541 		printf(_("%s: Kconfig file missing\n"), av[0]);
542 		exit(1);
543 	}
544 	conf_parse(name);
545 	//zconfdump(stdout);
546 	switch (input_mode) {
547 	case set_default:
548 		if (!defconfig_file)
549 			defconfig_file = conf_get_default_confname();
550 		if (conf_read(defconfig_file)) {
551 			printf("***\n"
552 				"*** Can't find default configuration \"%s\"!\n"
553 				"***\n", defconfig_file);
554 			exit(1);
555 		}
556 		break;
557 	case ask_silent:
558 		if (stat(".config", &tmpstat)) {
559 			printf(_("***\n"
560 				"*** You have not yet configured your "PROJECT_NAME"!\n"
561 				"***\n"
562 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
563 				"*** \"make menuconfig\" or \"make xconfig\").\n"
564 				"***\n"));
565 			exit(1);
566 		}
567 	case ask_all:
568 	case ask_new:
569 		conf_read(NULL);
570 		break;
571 	case set_no:
572 	case set_mod:
573 	case set_yes:
574 	case set_random:
575 		name = getenv("KCONFIG_ALLCONFIG");
576 		if (name && !stat(name, &tmpstat)) {
577 			conf_read_simple(name, S_DEF_USER);
578 			break;
579 		}
580 		switch (input_mode) {
581 		case set_no:	 name = "allno.config"; break;
582 		case set_mod:	 name = "allmod.config"; break;
583 		case set_yes:	 name = "allyes.config"; break;
584 		case set_random: name = "allrandom.config"; break;
585 		default: break;
586 		}
587 		if (!stat(name, &tmpstat))
588 			conf_read_simple(name, S_DEF_USER);
589 		else if (!stat("all.config", &tmpstat))
590 			conf_read_simple("all.config", S_DEF_USER);
591 		break;
592 	default:
593 		break;
594 	}
595 
596 	if (input_mode != ask_silent) {
597 		rootEntry = &rootmenu;
598 		conf(&rootmenu);
599 		if (input_mode == ask_all) {
600 			input_mode = ask_silent;
601 			valid_stdin = 1;
602 		}
603 	} else if (sym_change_count) {
604 		name = getenv("KCONFIG_NOSILENTUPDATE");
605 		if (name && *name) {
606 			fprintf(stderr, _("\n*** "PROJECT_NAME" configuration requires explicit update.\n\n"));
607 			return 1;
608 		}
609 	} else
610 		goto skip_check;
611 
612 	do {
613 		conf_cnt = 0;
614 		check_conf(&rootmenu);
615 	} while (conf_cnt);
616 
617 	if (!conf_write(NULL)) {
618 skip_check:
619 		if (!(input_mode == ask_silent && conf_write_autoconf()))
620 			return 0;
621 	}
622 	fprintf(stderr, _("\n*** Error writing "PROJECT_NAME" configuration.\n\n"));
623 	return 1;
624 }
625