Home | History | Annotate | Download | only in kconfig
      1 /*
      2  * Copyright (C) 2002 Roman Zippel <zippel (at) 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 your "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 (sym_change_count) {
    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 
    617 	if (!conf_write(NULL)) {
    618 skip_check:
    619 		if (!(input_mode == ask_silent && conf_write_autoconf()))
    620 			return 0;
    621 	}
    622 	fprintf(stderr, _("\n*** Error writing "PROJECT_NAME" configuration.\n\n"));
    623 	return 1;
    624 }
    625