xref: /openbmc/u-boot/scripts/kconfig/conf.c (revision fa61ef6b4980dbc009e93baadbfcb1daa359d74b)
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  #include <errno.h>
17  
18  #include "lkc.h"
19  
20  static void conf(struct menu *menu);
21  static void check_conf(struct menu *menu);
22  static void xfgets(char *str, int size, FILE *in);
23  
24  enum input_mode {
25  	oldaskconfig,
26  	silentoldconfig,
27  	oldconfig,
28  	allnoconfig,
29  	allyesconfig,
30  	allmodconfig,
31  	alldefconfig,
32  	randconfig,
33  	defconfig,
34  	savedefconfig,
35  	listnewconfig,
36  	olddefconfig,
37  } input_mode = oldaskconfig;
38  
39  static int indent = 1;
40  static int tty_stdio;
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  		/* fall through */
110  	case oldaskconfig:
111  		fflush(stdout);
112  		xfgets(line, 128, stdin);
113  		if (!tty_stdio)
114  			printf("\n");
115  		return 1;
116  	default:
117  		break;
118  	}
119  
120  	switch (type) {
121  	case S_INT:
122  	case S_HEX:
123  	case S_STRING:
124  		printf("%s\n", def);
125  		return 1;
126  	default:
127  		;
128  	}
129  	printf("%s", line);
130  	return 1;
131  }
132  
133  static int conf_string(struct menu *menu)
134  {
135  	struct symbol *sym = menu->sym;
136  	const char *def;
137  
138  	while (1) {
139  		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
140  		printf("(%s) ", sym->name);
141  		def = sym_get_string_value(sym);
142  		if (sym_get_string_value(sym))
143  			printf("[%s] ", def);
144  		if (!conf_askvalue(sym, def))
145  			return 0;
146  		switch (line[0]) {
147  		case '\n':
148  			break;
149  		case '?':
150  			/* print help */
151  			if (line[1] == '\n') {
152  				print_help(menu);
153  				def = NULL;
154  				break;
155  			}
156  			/* fall through */
157  		default:
158  			line[strlen(line)-1] = 0;
159  			def = line;
160  		}
161  		if (def && sym_set_string_value(sym, def))
162  			return 0;
163  	}
164  }
165  
166  static int conf_sym(struct menu *menu)
167  {
168  	struct symbol *sym = menu->sym;
169  	tristate oldval, newval;
170  
171  	while (1) {
172  		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
173  		if (sym->name)
174  			printf("(%s) ", sym->name);
175  		putchar('[');
176  		oldval = sym_get_tristate_value(sym);
177  		switch (oldval) {
178  		case no:
179  			putchar('N');
180  			break;
181  		case mod:
182  			putchar('M');
183  			break;
184  		case yes:
185  			putchar('Y');
186  			break;
187  		}
188  		if (oldval != no && sym_tristate_within_range(sym, no))
189  			printf("/n");
190  		if (oldval != mod && sym_tristate_within_range(sym, mod))
191  			printf("/m");
192  		if (oldval != yes && sym_tristate_within_range(sym, yes))
193  			printf("/y");
194  		if (menu_has_help(menu))
195  			printf("/?");
196  		printf("] ");
197  		if (!conf_askvalue(sym, sym_get_string_value(sym)))
198  			return 0;
199  		strip(line);
200  
201  		switch (line[0]) {
202  		case 'n':
203  		case 'N':
204  			newval = no;
205  			if (!line[1] || !strcmp(&line[1], "o"))
206  				break;
207  			continue;
208  		case 'm':
209  		case 'M':
210  			newval = mod;
211  			if (!line[1])
212  				break;
213  			continue;
214  		case 'y':
215  		case 'Y':
216  			newval = yes;
217  			if (!line[1] || !strcmp(&line[1], "es"))
218  				break;
219  			continue;
220  		case 0:
221  			newval = oldval;
222  			break;
223  		case '?':
224  			goto help;
225  		default:
226  			continue;
227  		}
228  		if (sym_set_tristate_value(sym, newval))
229  			return 0;
230  help:
231  		print_help(menu);
232  	}
233  }
234  
235  static int conf_choice(struct menu *menu)
236  {
237  	struct symbol *sym, *def_sym;
238  	struct menu *child;
239  	bool is_new;
240  
241  	sym = menu->sym;
242  	is_new = !sym_has_value(sym);
243  	if (sym_is_changable(sym)) {
244  		conf_sym(menu);
245  		sym_calc_value(sym);
246  		switch (sym_get_tristate_value(sym)) {
247  		case no:
248  			return 1;
249  		case mod:
250  			return 0;
251  		case yes:
252  			break;
253  		}
254  	} else {
255  		switch (sym_get_tristate_value(sym)) {
256  		case no:
257  			return 1;
258  		case mod:
259  			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
260  			return 0;
261  		case yes:
262  			break;
263  		}
264  	}
265  
266  	while (1) {
267  		int cnt, def;
268  
269  		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
270  		def_sym = sym_get_choice_value(sym);
271  		cnt = def = 0;
272  		line[0] = 0;
273  		for (child = menu->list; child; child = child->next) {
274  			if (!menu_is_visible(child))
275  				continue;
276  			if (!child->sym) {
277  				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
278  				continue;
279  			}
280  			cnt++;
281  			if (child->sym == def_sym) {
282  				def = cnt;
283  				printf("%*c", indent, '>');
284  			} else
285  				printf("%*c", indent, ' ');
286  			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
287  			if (child->sym->name)
288  				printf(" (%s)", child->sym->name);
289  			if (!sym_has_value(child->sym))
290  				printf(_(" (NEW)"));
291  			printf("\n");
292  		}
293  		printf(_("%*schoice"), indent - 1, "");
294  		if (cnt == 1) {
295  			printf("[1]: 1\n");
296  			goto conf_childs;
297  		}
298  		printf("[1-%d", cnt);
299  		if (menu_has_help(menu))
300  			printf("?");
301  		printf("]: ");
302  		switch (input_mode) {
303  		case oldconfig:
304  		case silentoldconfig:
305  			if (!is_new) {
306  				cnt = def;
307  				printf("%d\n", cnt);
308  				break;
309  			}
310  			check_stdin();
311  			/* fall through */
312  		case oldaskconfig:
313  			fflush(stdout);
314  			xfgets(line, 128, stdin);
315  			strip(line);
316  			if (line[0] == '?') {
317  				print_help(menu);
318  				continue;
319  			}
320  			if (!line[0])
321  				cnt = def;
322  			else if (isdigit(line[0]))
323  				cnt = atoi(line);
324  			else
325  				continue;
326  			break;
327  		default:
328  			break;
329  		}
330  
331  	conf_childs:
332  		for (child = menu->list; child; child = child->next) {
333  			if (!child->sym || !menu_is_visible(child))
334  				continue;
335  			if (!--cnt)
336  				break;
337  		}
338  		if (!child)
339  			continue;
340  		if (line[0] && line[strlen(line) - 1] == '?') {
341  			print_help(child);
342  			continue;
343  		}
344  		sym_set_choice_value(sym, child->sym);
345  		for (child = child->list; child; child = child->next) {
346  			indent += 2;
347  			conf(child);
348  			indent -= 2;
349  		}
350  		return 1;
351  	}
352  }
353  
354  static void conf(struct menu *menu)
355  {
356  	struct symbol *sym;
357  	struct property *prop;
358  	struct menu *child;
359  
360  	if (!menu_is_visible(menu))
361  		return;
362  
363  	sym = menu->sym;
364  	prop = menu->prompt;
365  	if (prop) {
366  		const char *prompt;
367  
368  		switch (prop->type) {
369  		case P_MENU:
370  			if ((input_mode == silentoldconfig ||
371  			     input_mode == listnewconfig ||
372  			     input_mode == olddefconfig) &&
373  			    rootEntry != menu) {
374  				check_conf(menu);
375  				return;
376  			}
377  			/* fall through */
378  		case P_COMMENT:
379  			prompt = menu_get_prompt(menu);
380  			if (prompt)
381  				printf("%*c\n%*c %s\n%*c\n",
382  					indent, '*',
383  					indent, '*', _(prompt),
384  					indent, '*');
385  		default:
386  			;
387  		}
388  	}
389  
390  	if (!sym)
391  		goto conf_childs;
392  
393  	if (sym_is_choice(sym)) {
394  		conf_choice(menu);
395  		if (sym->curr.tri != mod)
396  			return;
397  		goto conf_childs;
398  	}
399  
400  	switch (sym->type) {
401  	case S_INT:
402  	case S_HEX:
403  	case S_STRING:
404  		conf_string(menu);
405  		break;
406  	default:
407  		conf_sym(menu);
408  		break;
409  	}
410  
411  conf_childs:
412  	if (sym)
413  		indent += 2;
414  	for (child = menu->list; child; child = child->next)
415  		conf(child);
416  	if (sym)
417  		indent -= 2;
418  }
419  
420  static void check_conf(struct menu *menu)
421  {
422  	struct symbol *sym;
423  	struct menu *child;
424  
425  	if (!menu_is_visible(menu))
426  		return;
427  
428  	sym = menu->sym;
429  	if (sym && !sym_has_value(sym)) {
430  		if (sym_is_changable(sym) ||
431  		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
432  			if (input_mode == listnewconfig) {
433  				if (sym->name && !sym_is_choice_value(sym)) {
434  					printf("%s%s\n", CONFIG_, sym->name);
435  				}
436  			} else if (input_mode != olddefconfig) {
437  				if (!conf_cnt++)
438  					printf(_("*\n* Restart config...\n*\n"));
439  				rootEntry = menu_get_parent_menu(menu);
440  				conf(rootEntry);
441  			}
442  		}
443  	}
444  
445  	for (child = menu->list; child; child = child->next)
446  		check_conf(child);
447  }
448  
449  static struct option long_opts[] = {
450  	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
451  	{"oldconfig",       no_argument,       NULL, oldconfig},
452  	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
453  	{"defconfig",       optional_argument, NULL, defconfig},
454  	{"savedefconfig",   required_argument, NULL, savedefconfig},
455  	{"allnoconfig",     no_argument,       NULL, allnoconfig},
456  	{"allyesconfig",    no_argument,       NULL, allyesconfig},
457  	{"allmodconfig",    no_argument,       NULL, allmodconfig},
458  	{"alldefconfig",    no_argument,       NULL, alldefconfig},
459  	{"randconfig",      no_argument,       NULL, randconfig},
460  	{"listnewconfig",   no_argument,       NULL, listnewconfig},
461  	{"olddefconfig",    no_argument,       NULL, olddefconfig},
462  	/*
463  	 * oldnoconfig is an alias of olddefconfig, because people already
464  	 * are dependent on its behavior(sets new symbols to their default
465  	 * value but not 'n') with the counter-intuitive name.
466  	 */
467  	{"oldnoconfig",     no_argument,       NULL, olddefconfig},
468  	{NULL, 0, NULL, 0}
469  };
470  
471  static void conf_usage(const char *progname)
472  {
473  
474  	printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
475  	printf("[option] is _one_ of the following:\n");
476  	printf("  --listnewconfig         List new options\n");
477  	printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
478  	printf("  --oldconfig             Update a configuration using a provided .config as base\n");
479  	printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
480  	printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
481  	printf("  --oldnoconfig           An alias of olddefconfig\n");
482  	printf("  --defconfig <file>      New config with default defined in <file>\n");
483  	printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
484  	printf("  --allnoconfig           New config where all options are answered with no\n");
485  	printf("  --allyesconfig          New config where all options are answered with yes\n");
486  	printf("  --allmodconfig          New config where all options are answered with mod\n");
487  	printf("  --alldefconfig          New config with all symbols set to default\n");
488  	printf("  --randconfig            New config with random answer to all options\n");
489  }
490  
491  int main(int ac, char **av)
492  {
493  	const char *progname = av[0];
494  	int opt;
495  	const char *name, *defconfig_file = NULL /* gcc uninit */;
496  	struct stat tmpstat;
497  
498  	setlocale(LC_ALL, "");
499  	bindtextdomain(PACKAGE, LOCALEDIR);
500  	textdomain(PACKAGE);
501  
502  	tty_stdio = isatty(0) && isatty(1) && isatty(2);
503  
504  	while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
505  		if (opt == 's') {
506  			conf_set_message_callback(NULL);
507  			continue;
508  		}
509  		input_mode = (enum input_mode)opt;
510  		switch (opt) {
511  		case silentoldconfig:
512  			sync_kconfig = 1;
513  			break;
514  		case defconfig:
515  		case savedefconfig:
516  			defconfig_file = optarg;
517  			break;
518  		case randconfig:
519  		{
520  			struct timeval now;
521  			unsigned int seed;
522  			char *seed_env;
523  
524  			/*
525  			 * Use microseconds derived seed,
526  			 * compensate for systems where it may be zero
527  			 */
528  			gettimeofday(&now, NULL);
529  			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
530  
531  			seed_env = getenv("KCONFIG_SEED");
532  			if( seed_env && *seed_env ) {
533  				char *endp;
534  				int tmp = (int)strtol(seed_env, &endp, 0);
535  				if (*endp == '\0') {
536  					seed = tmp;
537  				}
538  			}
539  			fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
540  			srand(seed);
541  			break;
542  		}
543  		case oldaskconfig:
544  		case oldconfig:
545  		case allnoconfig:
546  		case allyesconfig:
547  		case allmodconfig:
548  		case alldefconfig:
549  		case listnewconfig:
550  		case olddefconfig:
551  			break;
552  		case '?':
553  			conf_usage(progname);
554  			exit(1);
555  			break;
556  		}
557  	}
558  	if (ac == optind) {
559  		printf(_("%s: Kconfig file missing\n"), av[0]);
560  		conf_usage(progname);
561  		exit(1);
562  	}
563  	name = av[optind];
564  	conf_parse(name);
565  	//zconfdump(stdout);
566  	if (sync_kconfig) {
567  		name = conf_get_configname();
568  		if (stat(name, &tmpstat)) {
569  			fprintf(stderr, _("***\n"
570  				"*** Configuration file \"%s\" not found!\n"
571  				"***\n"
572  				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
573  				"*** \"make menuconfig\" or \"make xconfig\").\n"
574  				"***\n"), name);
575  			exit(1);
576  		}
577  	}
578  
579  	switch (input_mode) {
580  	case defconfig:
581  		if (!defconfig_file)
582  			defconfig_file = conf_get_default_confname();
583  		if (conf_read(defconfig_file)) {
584  			printf(_("***\n"
585  				"*** Can't find default configuration \"%s\"!\n"
586  				"***\n"), defconfig_file);
587  			exit(1);
588  		}
589  		break;
590  	case savedefconfig:
591  	case silentoldconfig:
592  	case oldaskconfig:
593  	case oldconfig:
594  	case listnewconfig:
595  	case olddefconfig:
596  		conf_read(NULL);
597  		break;
598  	case allnoconfig:
599  	case allyesconfig:
600  	case allmodconfig:
601  	case alldefconfig:
602  	case randconfig:
603  		name = getenv("KCONFIG_ALLCONFIG");
604  		if (!name)
605  			break;
606  		if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
607  			if (conf_read_simple(name, S_DEF_USER)) {
608  				fprintf(stderr,
609  					_("*** Can't read seed configuration \"%s\"!\n"),
610  					name);
611  				exit(1);
612  			}
613  			break;
614  		}
615  		switch (input_mode) {
616  		case allnoconfig:	name = "allno.config"; break;
617  		case allyesconfig:	name = "allyes.config"; break;
618  		case allmodconfig:	name = "allmod.config"; break;
619  		case alldefconfig:	name = "alldef.config"; break;
620  		case randconfig:	name = "allrandom.config"; break;
621  		default: break;
622  		}
623  		if (conf_read_simple(name, S_DEF_USER) &&
624  		    conf_read_simple("all.config", S_DEF_USER)) {
625  			fprintf(stderr,
626  				_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
627  				name);
628  			exit(1);
629  		}
630  		break;
631  	default:
632  		break;
633  	}
634  
635  	if (sync_kconfig) {
636  		if (conf_get_changed()) {
637  			name = getenv("KCONFIG_NOSILENTUPDATE");
638  			if (name && *name) {
639  				fprintf(stderr,
640  					_("\n*** The configuration requires explicit update.\n\n"));
641  				return 1;
642  			}
643  		}
644  		valid_stdin = tty_stdio;
645  	}
646  
647  	switch (input_mode) {
648  	case allnoconfig:
649  		conf_set_all_new_symbols(def_no);
650  		break;
651  	case allyesconfig:
652  		conf_set_all_new_symbols(def_yes);
653  		break;
654  	case allmodconfig:
655  		conf_set_all_new_symbols(def_mod);
656  		break;
657  	case alldefconfig:
658  		conf_set_all_new_symbols(def_default);
659  		break;
660  	case randconfig:
661  		/* Really nothing to do in this loop */
662  		while (conf_set_all_new_symbols(def_random)) ;
663  		break;
664  	case defconfig:
665  		conf_set_all_new_symbols(def_default);
666  		break;
667  	case savedefconfig:
668  		break;
669  	case oldaskconfig:
670  		rootEntry = &rootmenu;
671  		conf(&rootmenu);
672  		input_mode = silentoldconfig;
673  		/* fall through */
674  	case oldconfig:
675  	case listnewconfig:
676  	case olddefconfig:
677  	case silentoldconfig:
678  		/* Update until a loop caused no more changes */
679  		do {
680  			conf_cnt = 0;
681  			check_conf(&rootmenu);
682  		} while (conf_cnt &&
683  			 (input_mode != listnewconfig &&
684  			  input_mode != olddefconfig));
685  		break;
686  	}
687  
688  	if (sync_kconfig) {
689  		/* silentoldconfig is used during the build so we shall update autoconf.
690  		 * All other commands are only used to generate a config.
691  		 */
692  		if (conf_get_changed() && conf_write(NULL)) {
693  			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
694  			exit(1);
695  		}
696  		if (conf_write_autoconf()) {
697  			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
698  			return 1;
699  		}
700  	} else if (input_mode == savedefconfig) {
701  		if (conf_write_defconfig(defconfig_file)) {
702  			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
703  				defconfig_file);
704  			return 1;
705  		}
706  	} else if (input_mode != listnewconfig) {
707  		if (conf_write(NULL)) {
708  			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
709  			exit(1);
710  		}
711  	}
712  	return 0;
713  }
714  
715  /*
716   * Helper function to facilitate fgets() by Jean Sacren.
717   */
718  void xfgets(char *str, int size, FILE *in)
719  {
720  	if (fgets(str, size, in) == NULL)
721  		fprintf(stderr, "\nError in reading or end of file.\n");
722  }
723