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