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