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