diff options
Diffstat (limited to 'scripts/kconfig/confdata.c')
| -rw-r--r-- | scripts/kconfig/confdata.c | 510 | 
1 files changed, 345 insertions, 165 deletions
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 9df80114b47..f88d90f2022 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -7,13 +7,13 @@  #include <ctype.h>  #include <errno.h>  #include <fcntl.h> +#include <stdarg.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h>  #include <time.h>  #include <unistd.h> -#define LKC_DIRECT_LINK  #include "lkc.h"  static void conf_warning(const char *fmt, ...) @@ -128,6 +128,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  			sym->flags |= def_flags;  			break;  		} +		/* fall through */  	case S_BOOLEAN:  		if (p[0] == 'y') {  			sym->def[def].tri = yes; @@ -139,8 +140,10 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  			sym->flags |= def_flags;  			break;  		} -		conf_warning("symbol value '%s' invalid for %s", p, sym->name); -		break; +		if (def != S_DEF_AUTO) +			conf_warning("symbol value '%s' invalid for %s", +				     p, sym->name); +		return 1;  	case S_OTHER:  		if (*p != '"') {  			for (p2 = p; *p2 && !isspace(*p2); p2++) @@ -148,6 +151,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  			sym->type = S_STRING;  			goto done;  		} +		/* fall through */  	case S_STRING:  		if (*p++ != '"')  			break; @@ -159,9 +163,11 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  			memmove(p2, p2 + 1, strlen(p2));  		}  		if (!p2) { -			conf_warning("invalid string found"); +			if (def != S_DEF_AUTO) +				conf_warning("invalid string found");  			return 1;  		} +		/* fall through */  	case S_INT:  	case S_HEX:  	done: @@ -169,7 +175,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  			sym->def[def].val = strdup(p);  			sym->flags |= def_flags;  		} else { -			conf_warning("symbol value '%s' invalid for %s", p, sym->name); +			if (def != S_DEF_AUTO) +				conf_warning("symbol value '%s' invalid for %s", +					     p, sym->name);  			return 1;  		}  		break; @@ -179,10 +187,66 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)  	return 0;  } +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ +	char *nline; +	size_t new_size = slen + 1; +	if (new_size > *n) { +		new_size += LINE_GROWTH - 1; +		new_size *= 2; +		nline = realloc(*lineptr, new_size); +		if (!nline) +			return -1; + +		*lineptr = nline; +		*n = new_size; +	} + +	(*lineptr)[slen] = c; + +	return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ +	char *line = *lineptr; +	size_t slen = 0; + +	for (;;) { +		int c = getc(stream); + +		switch (c) { +		case '\n': +			if (add_byte(c, &line, slen, n) < 0) +				goto e_out; +			slen++; +			/* fall through */ +		case EOF: +			if (add_byte('\0', &line, slen, n) < 0) +				goto e_out; +			*lineptr = line; +			if (slen == 0) +				return -1; +			return slen; +		default: +			if (add_byte(c, &line, slen, n) < 0) +				goto e_out; +			slen++; +		} +	} + +e_out: +	line[slen-1] = '\0'; +	*lineptr = line; +	return -1; +} +  int conf_read_simple(const char *name, int def)  {  	FILE *in = NULL; -	char line[1024]; +	char   *line = NULL; +	size_t  line_asize = 0;  	char *p, *p2;  	struct symbol *sym;  	int i, def_flags; @@ -237,13 +301,14 @@ load:  		case S_STRING:  			if (sym->def[def].val)  				free(sym->def[def].val); +			/* fall through */  		default:  			sym->def[def].val = NULL;  			sym->def[def].tri = no;  		}  	} -	while (fgets(line, sizeof(line), in)) { +	while (compat_getline(&line, &line_asize, in) != -1) {  		conf_lineno++;  		sym = NULL;  		if (line[0] == '#') { @@ -331,6 +396,7 @@ setsym:  			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);  		}  	} +	free(line);  	fclose(in);  	if (modules_sym) @@ -340,10 +406,8 @@ setsym:  int conf_read(const char *name)  { -	struct symbol *sym, *choice_sym; -	struct property *prop; -	struct expr *e; -	int i, flags; +	struct symbol *sym; +	int i;  	sym_set_change_count(0); @@ -353,7 +417,7 @@ int conf_read(const char *name)  	for_all_symbols(i, sym) {  		sym_calc_value(sym);  		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) -			goto sym_ok; +			continue;  		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {  			/* check that calculated value agrees with saved value */  			switch (sym->type) { @@ -362,29 +426,18 @@ int conf_read(const char *name)  				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))  					break;  				if (!sym_is_choice(sym)) -					goto sym_ok; +					continue; +				/* fall through */  			default:  				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) -					goto sym_ok; +					continue;  				break;  			}  		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))  			/* no previous value and not saved */ -			goto sym_ok; +			continue;  		conf_unsaved++;  		/* maybe print value in verbose mode... */ -	sym_ok: -		if (!sym_is_choice(sym)) -			continue; -		/* The choice symbol only has a set value (and thus is not new) -		 * if all its visible childs have values. -		 */ -		prop = sym_get_choice_prop(sym); -		flags = sym->flags; -		expr_list_for_each_sym(prop->expr, e, choice_sym) -			if (choice_sym->visible != no) -				flags &= choice_sym->flags; -		sym->flags &= flags | ~SYMBOL_DEF_USER;  	}  	for_all_symbols(i, sym) { @@ -417,65 +470,191 @@ int conf_read(const char *name)  	return 0;  } -/* Write a S_STRING */ -static void conf_write_string(bool headerfile, const char *name, -                              const char *str, FILE *out) +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)  { -	int l; -	if (headerfile) -		fprintf(out, "#define %s%s \"", CONFIG_, name); -	else -		fprintf(out, "%s%s=\"", CONFIG_, name); - -	while (1) { -		l = strcspn(str, "\"\\"); + +	switch (sym->type) { +	case S_BOOLEAN: +	case S_TRISTATE: +		if (*value == 'n') { +			bool skip_unset = (arg != NULL); + +			if (!skip_unset) +				fprintf(fp, "# %s%s is not set\n", +				    CONFIG_, sym->name); +			return; +		} +		break; +	default: +		break; +	} + +	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ +	const char *p = value; +	size_t l; + +	for (;;) { +		l = strcspn(p, "\n"); +		fprintf(fp, "#");  		if (l) { -			xfwrite(str, l, 1, out); -			str += l; +			fprintf(fp, " "); +			xfwrite(p, l, 1, fp); +			p += l;  		} -		if (!*str) +		fprintf(fp, "\n"); +		if (*p++ == '\0')  			break; -		fprintf(out, "\\%c", *str++);  	} -	fputs("\"\n", out);  } -static void conf_write_symbol(struct symbol *sym, enum symbol_type type, -                              FILE *out, bool write_no) +static struct conf_printer kconfig_printer_cb = +{ +	.print_symbol = kconfig_print_symbol, +	.print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)  { -	const char *str; -	switch (type) { +	switch (sym->type) {  	case S_BOOLEAN: -	case S_TRISTATE: -		switch (sym_get_tristate_value(sym)) { -		case no: -			if (write_no) -				fprintf(out, "# %s%s is not set\n", -				    CONFIG_, sym->name); -			break; -		case mod: -			fprintf(out, "%s%s=m\n", CONFIG_, sym->name); -			break; -		case yes: -			fprintf(out, "%s%s=y\n", CONFIG_, sym->name); +	case S_TRISTATE: { +		const char *suffix = ""; + +		switch (*value) { +		case 'n':  			break; +		case 'm': +			suffix = "_MODULE"; +			/* fall through */ +		default: +			fprintf(fp, "#define %s%s%s 1\n", +			    CONFIG_, sym->name, suffix);  		}  		break; -	case S_STRING: -		conf_write_string(false, sym->name, sym_get_string_value(sym), out); +	} +	case S_HEX: { +		const char *prefix = ""; + +		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) +			prefix = "0x"; +		fprintf(fp, "#define %s%s %s%s\n", +		    CONFIG_, sym->name, prefix, value);  		break; -	case S_HEX: +	} +	case S_STRING:  	case S_INT: -		str = sym_get_string_value(sym); -		fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str); +		fprintf(fp, "#define %s%s %s\n", +		    CONFIG_, sym->name, value); +		break; +	default:  		break; +	} + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ +	const char *p = value; +	size_t l; + +	fprintf(fp, "/*\n"); +	for (;;) { +		l = strcspn(p, "\n"); +		fprintf(fp, " *"); +		if (l) { +			fprintf(fp, " "); +			xfwrite(p, l, 1, fp); +			p += l; +		} +		fprintf(fp, "\n"); +		if (*p++ == '\0') +			break; +	} +	fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ +	.print_symbol = header_print_symbol, +	.print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + +	if (sym->type == S_TRISTATE && *value != 'n') +		fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ +	.print_symbol = tristate_print_symbol, +	.print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, +			      struct conf_printer *printer, void *printer_arg) +{ +	const char *str; + +	switch (sym->type) {  	case S_OTHER:  	case S_UNKNOWN:  		break; +	case S_STRING: +		str = sym_get_string_value(sym); +		str = sym_escape_string_value(str); +		printer->print_symbol(fp, sym, str, printer_arg); +		free((void *)str); +		break; +	default: +		str = sym_get_string_value(sym); +		printer->print_symbol(fp, sym, str, printer_arg);  	}  } +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ +	char buf[256]; + +	snprintf(buf, sizeof(buf), +	    "\n" +	    "Automatically generated file; DO NOT EDIT.\n" +	    "%s\n", +	    rootmenu.prompt->text); + +	printer->print_comment(fp, buf, printer_arg); +} +  /*   * Write out a minimal config.   * All values that has default values are skipped as this is redundant. @@ -532,7 +711,7 @@ int conf_write_defconfig(const char *filename)  						goto next_menu;  				}  			} -			conf_write_symbol(sym, sym->type, out, true); +			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);  		}  next_menu:  		if (menu->list != NULL) { @@ -561,9 +740,6 @@ int conf_write(const char *name)  	const char *basename;  	const char *str;  	char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; -	enum symbol_type type; -	time_t now; -	int use_timestamp = 1;  	char *env;  	dirname[0] = 0; @@ -600,19 +776,7 @@ int conf_write(const char *name)  	if (!out)  		return 1; -	time(&now); -	env = getenv("KCONFIG_NOTIMESTAMP"); -	if (env && *env) -		use_timestamp = 0; - -	fprintf(out, _("#\n" -		       "# Automatically generated make config: don't edit\n" -		       "# %s\n" -		       "%s%s" -		       "#\n"), -		     rootmenu.prompt->text, -		     use_timestamp ? "# " : "", -		     use_timestamp ? ctime(&now) : ""); +	conf_write_heading(out, &kconfig_printer_cb, NULL);  	if (!conf_get_changed())  		sym_clear_all_valid(); @@ -633,14 +797,8 @@ int conf_write(const char *name)  			if (!(sym->flags & SYMBOL_WRITE))  				goto next;  			sym->flags &= ~SYMBOL_WRITE; -			type = sym->type; -			if (type == S_TRISTATE) { -				sym_calc_value(modules_sym); -				if (modules_sym->curr.tri == no) -					type = S_BOOLEAN; -			} -			/* Write config symbol to file */ -			conf_write_symbol(sym, type, out, true); + +			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);  		}  next: @@ -789,10 +947,8 @@ out:  int conf_write_autoconf(void)  {  	struct symbol *sym; -	const char *str;  	const char *name;  	FILE *out, *tristate, *out_h; -	time_t now;  	int i;  	sym_clear_all_valid(); @@ -819,72 +975,23 @@ int conf_write_autoconf(void)  		return 1;  	} -	time(&now); -	fprintf(out, "#\n" -		     "# Automatically generated make config: don't edit\n" -		     "# %s\n" -		     "# %s" -		     "#\n", -		     rootmenu.prompt->text, ctime(&now)); -	fprintf(tristate, "#\n" -			  "# Automatically generated - do not edit\n" -			  "\n"); -	fprintf(out_h, "/*\n" -		       " * Automatically generated C config: don't edit\n" -		       " * %s\n" -		       " * %s" -		       " */\n" -		       "#define AUTOCONF_INCLUDED\n", -		       rootmenu.prompt->text, ctime(&now)); +	conf_write_heading(out, &kconfig_printer_cb, NULL); + +	conf_write_heading(tristate, &tristate_printer_cb, NULL); + +	conf_write_heading(out_h, &header_printer_cb, NULL);  	for_all_symbols(i, sym) {  		sym_calc_value(sym);  		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)  			continue; -		/* write symbol to config file */ -		conf_write_symbol(sym, sym->type, out, false); +		/* write symbol to auto.conf, tristate and header files */ +		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); -		/* update autoconf and tristate files */ -		switch (sym->type) { -		case S_BOOLEAN: -		case S_TRISTATE: -			switch (sym_get_tristate_value(sym)) { -			case no: -				break; -			case mod: -				fprintf(tristate, "%s%s=M\n", -				    CONFIG_, sym->name); -				fprintf(out_h, "#define %s%s_MODULE 1\n", -				    CONFIG_, sym->name); -				break; -			case yes: -				if (sym->type == S_TRISTATE) -					fprintf(tristate,"%s%s=Y\n", -					    CONFIG_, sym->name); -				fprintf(out_h, "#define %s%s 1\n", -				    CONFIG_, sym->name); -				break; -			} -			break; -		case S_STRING: -			conf_write_string(true, sym->name, sym_get_string_value(sym), out_h); -			break; -		case S_HEX: -			str = sym_get_string_value(sym); -			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { -				fprintf(out_h, "#define %s%s 0x%s\n", -				    CONFIG_, sym->name, str); -				break; -			} -		case S_INT: -			str = sym_get_string_value(sym); -			fprintf(out_h, "#define %s%s %s\n", -			    CONFIG_, sym->name, str); -			break; -		default: -			break; -		} +		conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + +		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);  	}  	fclose(out);  	fclose(tristate); @@ -938,7 +1045,7 @@ void conf_set_changed_callback(void (*fn)(void))  	conf_changed_callback = fn;  } -static void randomize_choice_values(struct symbol *csym) +static bool randomize_choice_values(struct symbol *csym)  {  	struct property *prop;  	struct symbol *sym; @@ -946,12 +1053,12 @@ static void randomize_choice_values(struct symbol *csym)  	int cnt, def;  	/* -	 * If choice is mod then we may have more items slected +	 * If choice is mod then we may have more items selected  	 * and if no then no-one.  	 * In both cases stop.  	 */  	if (csym->curr.tri != yes) -		return; +		return false;  	prop = sym_get_choice_prop(csym); @@ -975,13 +1082,18 @@ static void randomize_choice_values(struct symbol *csym)  		else {  			sym->def[S_DEF_USER].tri = no;  		} +		sym->flags |= SYMBOL_DEF_USER; +		/* clear VALID to get value calculated */ +		sym->flags &= ~SYMBOL_VALID;  	}  	csym->flags |= SYMBOL_DEF_USER;  	/* clear VALID to get value calculated */  	csym->flags &= ~(SYMBOL_VALID); + +	return true;  } -static void set_all_choice_values(struct symbol *csym) +void set_all_choice_values(struct symbol *csym)  {  	struct property *prop;  	struct symbol *sym; @@ -998,20 +1110,66 @@ static void set_all_choice_values(struct symbol *csym)  	}  	csym->flags |= SYMBOL_DEF_USER;  	/* clear VALID to get value calculated */ -	csym->flags &= ~(SYMBOL_VALID); +	csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);  } -void conf_set_all_new_symbols(enum conf_def_mode mode) +bool conf_set_all_new_symbols(enum conf_def_mode mode)  {  	struct symbol *sym, *csym; -	int i, cnt; +	int i, cnt, pby, pty, ptm;	/* pby: probability of boolean  = y +					 * pty: probability of tristate = y +					 * ptm: probability of tristate = m +					 */ + +	pby = 50; pty = ptm = 33; /* can't go as the default in switch-case +				   * below, otherwise gcc whines about +				   * -Wmaybe-uninitialized */ +	if (mode == def_random) { +		int n, p[3]; +		char *env = getenv("KCONFIG_PROBABILITY"); +		n = 0; +		while( env && *env ) { +			char *endp; +			int tmp = strtol( env, &endp, 10 ); +			if( tmp >= 0 && tmp <= 100 ) { +				p[n++] = tmp; +			} else { +				errno = ERANGE; +				perror( "KCONFIG_PROBABILITY" ); +				exit( 1 ); +			} +			env = (*endp == ':') ? endp+1 : endp; +			if( n >=3 ) { +				break; +			} +		} +		switch( n ) { +		case 1: +			pby = p[0]; ptm = pby/2; pty = pby-ptm; +			break; +		case 2: +			pty = p[0]; ptm = p[1]; pby = pty + ptm; +			break; +		case 3: +			pby = p[0]; pty = p[1]; ptm = p[2]; +			break; +		} + +		if( pty+ptm > 100 ) { +			errno = ERANGE; +			perror( "KCONFIG_PROBABILITY" ); +			exit( 1 ); +		} +	} +	bool has_changed = false;  	for_all_symbols(i, sym) { -		if (sym_has_value(sym)) +		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))  			continue;  		switch (sym_get_type(sym)) {  		case S_BOOLEAN:  		case S_TRISTATE: +			has_changed = true;  			switch (mode) {  			case def_yes:  				sym->def[S_DEF_USER].tri = yes; @@ -1020,11 +1178,21 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)  				sym->def[S_DEF_USER].tri = mod;  				break;  			case def_no: -				sym->def[S_DEF_USER].tri = no; +				if (sym->flags & SYMBOL_ALLNOCONFIG_Y) +					sym->def[S_DEF_USER].tri = yes; +				else +					sym->def[S_DEF_USER].tri = no;  				break;  			case def_random: -				cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2; -				sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt); +				sym->def[S_DEF_USER].tri = no; +				cnt = rand() % 100; +				if (sym->type == S_TRISTATE) { +					if (cnt < pty) +						sym->def[S_DEF_USER].tri = yes; +					else if (cnt < (pty+ptm)) +						sym->def[S_DEF_USER].tri = mod; +				} else if (cnt < pby) +					sym->def[S_DEF_USER].tri = yes;  				break;  			default:  				continue; @@ -1042,21 +1210,33 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)  	/*  	 * We have different type of choice blocks. -	 * If curr.tri equal to mod then we can select several +	 * If curr.tri equals to mod then we can select several  	 * choice symbols in one block.  	 * In this case we do nothing. -	 * If curr.tri equal yes then only one symbol can be +	 * If curr.tri equals yes then only one symbol can be  	 * selected in a choice block and we set it to yes,  	 * and the rest to no.  	 */ +	if (mode != def_random) { +		for_all_symbols(i, csym) { +			if ((sym_is_choice(csym) && !sym_has_value(csym)) || +			    sym_is_choice_value(csym)) +				csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; +		} +	} +  	for_all_symbols(i, csym) {  		if (sym_has_value(csym) || !sym_is_choice(csym))  			continue;  		sym_calc_value(csym);  		if (mode == def_random) -			randomize_choice_values(csym); -		else +			has_changed = randomize_choice_values(csym); +		else {  			set_all_choice_values(csym); +			has_changed = true; +		}  	} + +	return has_changed;  }  | 
