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