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