kconfig/confdata.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Apr 15 16:45:11 2007 +0000 (2007-04-15)
changeset 39 af42eec9d383
parent 1 eeea35fbf182
child 94 f32c4f663805
permissions -rw-r--r--
Update to latest kconfig from linux-2.6.20.7.
I'm not sure of the improvements, but at least we're up-to-date, and updating in the future will be easier.
yann@1
     1
/*
yann@1
     2
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
yann@1
     3
 * Released under the terms of the GNU GPL v2.0.
yann@1
     4
 */
yann@1
     5
yann@1
     6
#include <sys/stat.h>
yann@1
     7
#include <ctype.h>
yann@1
     8
#include <fcntl.h>
yann@1
     9
#include <stdio.h>
yann@1
    10
#include <stdlib.h>
yann@1
    11
#include <string.h>
yann@1
    12
#include <time.h>
yann@1
    13
#include <unistd.h>
yann@1
    14
yann@1
    15
#define LKC_DIRECT_LINK
yann@1
    16
#include "lkc.h"
yann@1
    17
yann@1
    18
static void conf_warning(const char *fmt, ...)
yann@1
    19
	__attribute__ ((format (printf, 1, 2)));
yann@1
    20
yann@1
    21
static const char *conf_filename;
yann@1
    22
static int conf_lineno, conf_warnings, conf_unsaved;
yann@1
    23
yann@1
    24
const char conf_defname[] = "arch/$ARCH/defconfig";
yann@1
    25
yann@1
    26
static void conf_warning(const char *fmt, ...)
yann@1
    27
{
yann@1
    28
	va_list ap;
yann@1
    29
	va_start(ap, fmt);
yann@1
    30
	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
yann@1
    31
	vfprintf(stderr, fmt, ap);
yann@1
    32
	fprintf(stderr, "\n");
yann@1
    33
	va_end(ap);
yann@1
    34
	conf_warnings++;
yann@1
    35
}
yann@1
    36
yann@1
    37
const char *conf_get_configname(void)
yann@1
    38
{
yann@1
    39
	char *name = getenv("KCONFIG_CONFIG");
yann@1
    40
yann@1
    41
	return name ? name : ".config";
yann@1
    42
}
yann@1
    43
yann@1
    44
static char *conf_expand_value(const char *in)
yann@1
    45
{
yann@1
    46
	struct symbol *sym;
yann@1
    47
	const char *src;
yann@1
    48
	static char res_value[SYMBOL_MAXLENGTH];
yann@1
    49
	char *dst, name[SYMBOL_MAXLENGTH];
yann@1
    50
yann@1
    51
	res_value[0] = 0;
yann@1
    52
	dst = name;
yann@1
    53
	while ((src = strchr(in, '$'))) {
yann@1
    54
		strncat(res_value, in, src - in);
yann@1
    55
		src++;
yann@1
    56
		dst = name;
yann@1
    57
		while (isalnum(*src) || *src == '_')
yann@1
    58
			*dst++ = *src++;
yann@1
    59
		*dst = 0;
yann@1
    60
		sym = sym_lookup(name, 0);
yann@1
    61
		sym_calc_value(sym);
yann@1
    62
		strcat(res_value, sym_get_string_value(sym));
yann@1
    63
		in = src;
yann@1
    64
	}
yann@1
    65
	strcat(res_value, in);
yann@1
    66
yann@1
    67
	return res_value;
yann@1
    68
}
yann@1
    69
yann@1
    70
char *conf_get_default_confname(void)
yann@1
    71
{
yann@1
    72
	struct stat buf;
yann@1
    73
	static char fullname[PATH_MAX+1];
yann@1
    74
	char *env, *name;
yann@1
    75
yann@1
    76
	name = conf_expand_value(conf_defname);
yann@1
    77
	env = getenv(SRCTREE);
yann@1
    78
	if (env) {
yann@1
    79
		sprintf(fullname, "%s/%s", env, name);
yann@1
    80
		if (!stat(fullname, &buf))
yann@1
    81
			return fullname;
yann@1
    82
	}
yann@1
    83
	return name;
yann@1
    84
}
yann@1
    85
yann@1
    86
int conf_read_simple(const char *name, int def)
yann@1
    87
{
yann@1
    88
	FILE *in = NULL;
yann@1
    89
	char line[1024];
yann@1
    90
	char *p, *p2;
yann@1
    91
	struct symbol *sym;
yann@1
    92
	int i, def_flags;
yann@1
    93
yann@1
    94
	if (name) {
yann@1
    95
		in = zconf_fopen(name);
yann@1
    96
	} else {
yann@1
    97
		struct property *prop;
yann@1
    98
yann@1
    99
		name = conf_get_configname();
yann@1
   100
		in = zconf_fopen(name);
yann@1
   101
		if (in)
yann@1
   102
			goto load;
yann@39
   103
		sym_add_change_count(1);
yann@1
   104
		if (!sym_defconfig_list)
yann@1
   105
			return 1;
yann@1
   106
yann@1
   107
		for_all_defaults(sym_defconfig_list, prop) {
yann@1
   108
			if (expr_calc_value(prop->visible.expr) == no ||
yann@1
   109
			    prop->expr->type != E_SYMBOL)
yann@1
   110
				continue;
yann@1
   111
			name = conf_expand_value(prop->expr->left.sym->name);
yann@1
   112
			in = zconf_fopen(name);
yann@1
   113
			if (in) {
yann@1
   114
				printf(_("#\n"
yann@1
   115
					 "# using defaults found in %s\n"
yann@1
   116
					 "#\n"), name);
yann@1
   117
				goto load;
yann@1
   118
			}
yann@1
   119
		}
yann@1
   120
	}
yann@1
   121
	if (!in)
yann@1
   122
		return 1;
yann@1
   123
yann@1
   124
load:
yann@1
   125
	conf_filename = name;
yann@1
   126
	conf_lineno = 0;
yann@1
   127
	conf_warnings = 0;
yann@1
   128
	conf_unsaved = 0;
yann@1
   129
yann@1
   130
	def_flags = SYMBOL_DEF << def;
yann@1
   131
	for_all_symbols(i, sym) {
yann@1
   132
		sym->flags |= SYMBOL_CHANGED;
yann@1
   133
		sym->flags &= ~(def_flags|SYMBOL_VALID);
yann@1
   134
		if (sym_is_choice(sym))
yann@1
   135
			sym->flags |= def_flags;
yann@1
   136
		switch (sym->type) {
yann@1
   137
		case S_INT:
yann@1
   138
		case S_HEX:
yann@1
   139
		case S_STRING:
yann@1
   140
			if (sym->def[def].val)
yann@1
   141
				free(sym->def[def].val);
yann@1
   142
		default:
yann@1
   143
			sym->def[def].val = NULL;
yann@1
   144
			sym->def[def].tri = no;
yann@1
   145
		}
yann@1
   146
	}
yann@1
   147
yann@1
   148
	while (fgets(line, sizeof(line), in)) {
yann@1
   149
		conf_lineno++;
yann@1
   150
		sym = NULL;
yann@1
   151
		switch (line[0]) {
yann@1
   152
		case '#':
yann@1
   153
			if (memcmp(line + 2, "CT_", 3))
yann@1
   154
				continue;
yann@1
   155
			p = strchr(line + 5, ' ');
yann@1
   156
			if (!p)
yann@1
   157
				continue;
yann@1
   158
			*p++ = 0;
yann@1
   159
			if (strncmp(p, "is not set", 10))
yann@1
   160
				continue;
yann@1
   161
			if (def == S_DEF_USER) {
yann@1
   162
				sym = sym_find(line + 5);
yann@1
   163
				if (!sym) {
yann@1
   164
					conf_warning("trying to assign nonexistent symbol %s", line + 5);
yann@1
   165
					break;
yann@1
   166
				}
yann@1
   167
			} else {
yann@1
   168
				sym = sym_lookup(line + 5, 0);
yann@1
   169
				if (sym->type == S_UNKNOWN)
yann@1
   170
					sym->type = S_BOOLEAN;
yann@1
   171
			}
yann@1
   172
			if (sym->flags & def_flags) {
yann@1
   173
				conf_warning("trying to reassign symbol %s", sym->name);
yann@1
   174
				break;
yann@1
   175
			}
yann@1
   176
			switch (sym->type) {
yann@1
   177
			case S_BOOLEAN:
yann@1
   178
			case S_TRISTATE:
yann@1
   179
				sym->def[def].tri = no;
yann@1
   180
				sym->flags |= def_flags;
yann@1
   181
				break;
yann@1
   182
			default:
yann@1
   183
				;
yann@1
   184
			}
yann@1
   185
			break;
yann@1
   186
		case 'C':
yann@1
   187
			if (memcmp(line, "CT_", 3)) {
yann@1
   188
				conf_warning("unexpected data");
yann@1
   189
				continue;
yann@1
   190
			}
yann@1
   191
			p = strchr(line + 3, '=');
yann@1
   192
			if (!p)
yann@1
   193
				continue;
yann@1
   194
			*p++ = 0;
yann@1
   195
			p2 = strchr(p, '\n');
yann@1
   196
			if (p2) {
yann@1
   197
				*p2-- = 0;
yann@1
   198
				if (*p2 == '\r')
yann@1
   199
					*p2 = 0;
yann@1
   200
			}
yann@1
   201
			if (def == S_DEF_USER) {
yann@1
   202
				sym = sym_find(line + 3);
yann@1
   203
				if (!sym) {
yann@1
   204
					conf_warning("trying to assign nonexistent symbol %s", line + 3);
yann@1
   205
					break;
yann@1
   206
				}
yann@1
   207
			} else {
yann@1
   208
				sym = sym_lookup(line + 3, 0);
yann@1
   209
				if (sym->type == S_UNKNOWN)
yann@1
   210
					sym->type = S_OTHER;
yann@1
   211
			}
yann@1
   212
			if (sym->flags & def_flags) {
yann@1
   213
				conf_warning("trying to reassign symbol %s", sym->name);
yann@1
   214
				break;
yann@1
   215
			}
yann@1
   216
			switch (sym->type) {
yann@1
   217
			case S_TRISTATE:
yann@1
   218
				if (p[0] == 'm') {
yann@1
   219
					sym->def[def].tri = mod;
yann@1
   220
					sym->flags |= def_flags;
yann@1
   221
					break;
yann@1
   222
				}
yann@1
   223
			case S_BOOLEAN:
yann@1
   224
				if (p[0] == 'y') {
yann@1
   225
					sym->def[def].tri = yes;
yann@1
   226
					sym->flags |= def_flags;
yann@1
   227
					break;
yann@1
   228
				}
yann@1
   229
				if (p[0] == 'n') {
yann@1
   230
					sym->def[def].tri = no;
yann@1
   231
					sym->flags |= def_flags;
yann@1
   232
					break;
yann@1
   233
				}
yann@1
   234
				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
yann@1
   235
				break;
yann@1
   236
			case S_OTHER:
yann@1
   237
				if (*p != '"') {
yann@1
   238
					for (p2 = p; *p2 && !isspace(*p2); p2++)
yann@1
   239
						;
yann@1
   240
					sym->type = S_STRING;
yann@1
   241
					goto done;
yann@1
   242
				}
yann@1
   243
			case S_STRING:
yann@1
   244
				if (*p++ != '"')
yann@1
   245
					break;
yann@1
   246
				for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
yann@1
   247
					if (*p2 == '"') {
yann@1
   248
						*p2 = 0;
yann@1
   249
						break;
yann@1
   250
					}
yann@1
   251
					memmove(p2, p2 + 1, strlen(p2));
yann@1
   252
				}
yann@1
   253
				if (!p2) {
yann@1
   254
					conf_warning("invalid string found");
yann@1
   255
					continue;
yann@1
   256
				}
yann@1
   257
			case S_INT:
yann@1
   258
			case S_HEX:
yann@1
   259
			done:
yann@1
   260
				if (sym_string_valid(sym, p)) {
yann@1
   261
					sym->def[def].val = strdup(p);
yann@1
   262
					sym->flags |= def_flags;
yann@1
   263
				} else {
yann@1
   264
					conf_warning("symbol value '%s' invalid for %s", p, sym->name);
yann@1
   265
					continue;
yann@1
   266
				}
yann@1
   267
				break;
yann@1
   268
			default:
yann@1
   269
				;
yann@1
   270
			}
yann@1
   271
			break;
yann@1
   272
		case '\r':
yann@1
   273
		case '\n':
yann@1
   274
			break;
yann@1
   275
		default:
yann@1
   276
			conf_warning("unexpected data");
yann@1
   277
			continue;
yann@1
   278
		}
yann@1
   279
		if (sym && sym_is_choice_value(sym)) {
yann@1
   280
			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
yann@1
   281
			switch (sym->def[def].tri) {
yann@1
   282
			case no:
yann@1
   283
				break;
yann@1
   284
			case mod:
yann@1
   285
				if (cs->def[def].tri == yes) {
yann@1
   286
					conf_warning("%s creates inconsistent choice state", sym->name);
yann@1
   287
					cs->flags &= ~def_flags;
yann@1
   288
				}
yann@1
   289
				break;
yann@1
   290
			case yes:
yann@1
   291
				if (cs->def[def].tri != no) {
yann@1
   292
					conf_warning("%s creates inconsistent choice state", sym->name);
yann@1
   293
					cs->flags &= ~def_flags;
yann@1
   294
				} else
yann@1
   295
					cs->def[def].val = sym;
yann@1
   296
				break;
yann@1
   297
			}
yann@1
   298
			cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri);
yann@1
   299
		}
yann@1
   300
	}
yann@1
   301
	fclose(in);
yann@1
   302
yann@1
   303
	if (modules_sym)
yann@1
   304
		sym_calc_value(modules_sym);
yann@1
   305
	return 0;
yann@1
   306
}
yann@1
   307
yann@1
   308
int conf_read(const char *name)
yann@1
   309
{
yann@1
   310
	struct symbol *sym;
yann@1
   311
	struct property *prop;
yann@1
   312
	struct expr *e;
yann@1
   313
	int i, flags;
yann@1
   314
yann@39
   315
	sym_set_change_count(0);
yann@1
   316
yann@1
   317
	if (conf_read_simple(name, S_DEF_USER))
yann@1
   318
		return 1;
yann@1
   319
yann@1
   320
	for_all_symbols(i, sym) {
yann@1
   321
		sym_calc_value(sym);
yann@1
   322
		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
yann@1
   323
			goto sym_ok;
yann@1
   324
		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
yann@1
   325
			/* check that calculated value agrees with saved value */
yann@1
   326
			switch (sym->type) {
yann@1
   327
			case S_BOOLEAN:
yann@1
   328
			case S_TRISTATE:
yann@1
   329
				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
yann@1
   330
					break;
yann@1
   331
				if (!sym_is_choice(sym))
yann@1
   332
					goto sym_ok;
yann@1
   333
			default:
yann@1
   334
				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
yann@1
   335
					goto sym_ok;
yann@1
   336
				break;
yann@1
   337
			}
yann@1
   338
		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
yann@1
   339
			/* no previous value and not saved */
yann@1
   340
			goto sym_ok;
yann@1
   341
		conf_unsaved++;
yann@1
   342
		/* maybe print value in verbose mode... */
yann@1
   343
	sym_ok:
yann@1
   344
		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
yann@1
   345
			if (sym->visible == no)
yann@1
   346
				sym->flags &= ~SYMBOL_DEF_USER;
yann@1
   347
			switch (sym->type) {
yann@1
   348
			case S_STRING:
yann@1
   349
			case S_INT:
yann@1
   350
			case S_HEX:
yann@1
   351
				if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
yann@1
   352
					sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
yann@1
   353
			default:
yann@1
   354
				break;
yann@1
   355
			}
yann@1
   356
		}
yann@1
   357
		if (!sym_is_choice(sym))
yann@1
   358
			continue;
yann@1
   359
		prop = sym_get_choice_prop(sym);
yann@1
   360
		flags = sym->flags;
yann@1
   361
		for (e = prop->expr; e; e = e->left.expr)
yann@1
   362
			if (e->right.sym->visible != no)
yann@1
   363
				flags &= e->right.sym->flags;
yann@1
   364
		sym->flags &= flags | ~SYMBOL_DEF_USER;
yann@1
   365
	}
yann@1
   366
yann@39
   367
	sym_add_change_count(conf_warnings || conf_unsaved);
yann@1
   368
yann@1
   369
	return 0;
yann@1
   370
}
yann@1
   371
yann@1
   372
int conf_write(const char *name)
yann@1
   373
{
yann@1
   374
	FILE *out;
yann@1
   375
	struct symbol *sym;
yann@1
   376
	struct menu *menu;
yann@1
   377
	const char *basename;
yann@1
   378
	char dirname[128], tmpname[128], newname[128];
yann@39
   379
	int type, l;
yann@1
   380
	const char *str;
yann@1
   381
	time_t now;
yann@1
   382
	int use_timestamp = 1;
yann@1
   383
	char *env;
yann@1
   384
yann@1
   385
	dirname[0] = 0;
yann@1
   386
	if (name && name[0]) {
yann@1
   387
		struct stat st;
yann@1
   388
		char *slash;
yann@1
   389
yann@1
   390
		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
yann@1
   391
			strcpy(dirname, name);
yann@1
   392
			strcat(dirname, "/");
yann@1
   393
			basename = conf_get_configname();
yann@1
   394
		} else if ((slash = strrchr(name, '/'))) {
yann@1
   395
			int size = slash - name + 1;
yann@1
   396
			memcpy(dirname, name, size);
yann@1
   397
			dirname[size] = 0;
yann@1
   398
			if (slash[1])
yann@1
   399
				basename = slash + 1;
yann@1
   400
			else
yann@1
   401
				basename = conf_get_configname();
yann@1
   402
		} else
yann@1
   403
			basename = name;
yann@1
   404
	} else
yann@1
   405
		basename = conf_get_configname();
yann@1
   406
yann@1
   407
	sprintf(newname, "%s%s", dirname, basename);
yann@1
   408
	env = getenv("KCONFIG_OVERWRITECONFIG");
yann@1
   409
	if (!env || !*env) {
yann@1
   410
		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
yann@1
   411
		out = fopen(tmpname, "w");
yann@1
   412
	} else {
yann@1
   413
		*tmpname = 0;
yann@1
   414
		out = fopen(newname, "w");
yann@1
   415
	}
yann@1
   416
	if (!out)
yann@1
   417
		return 1;
yann@1
   418
yann@1
   419
	sym = sym_lookup("PROJECTVERSION", 0);
yann@1
   420
	sym_calc_value(sym);
yann@1
   421
	time(&now);
yann@1
   422
	env = getenv("KCONFIG_NOTIMESTAMP");
yann@1
   423
	if (env && *env)
yann@1
   424
		use_timestamp = 0;
yann@1
   425
yann@1
   426
	fprintf(out, _("#\n"
yann@1
   427
		       "# Automatically generated make config: don't edit\n"
yann@1
   428
		       "# "PROJECT_NAME" version: %s\n"
yann@1
   429
		       "%s%s"
yann@1
   430
		       "#\n"),
yann@1
   431
		     sym_get_string_value(sym),
yann@1
   432
		     use_timestamp ? "# " : "",
yann@1
   433
		     use_timestamp ? ctime(&now) : "");
yann@1
   434
yann@39
   435
	if (!conf_get_changed())
yann@1
   436
		sym_clear_all_valid();
yann@1
   437
yann@1
   438
	menu = rootmenu.list;
yann@1
   439
	while (menu) {
yann@1
   440
		sym = menu->sym;
yann@1
   441
		if (!sym) {
yann@1
   442
			if (!menu_is_visible(menu))
yann@1
   443
				goto next;
yann@1
   444
			str = menu_get_prompt(menu);
yann@1
   445
			fprintf(out, "\n"
yann@1
   446
				     "#\n"
yann@1
   447
				     "# %s\n"
yann@1
   448
				     "#\n", str);
yann@1
   449
		} else if (!(sym->flags & SYMBOL_CHOICE)) {
yann@1
   450
			sym_calc_value(sym);
yann@39
   451
			if (!(sym->flags & SYMBOL_WRITE))
yann@1
   452
				goto next;
yann@39
   453
			sym->flags &= ~SYMBOL_WRITE;
yann@1
   454
			type = sym->type;
yann@1
   455
			if (type == S_TRISTATE) {
yann@1
   456
				sym_calc_value(modules_sym);
yann@1
   457
				if (modules_sym->curr.tri == no)
yann@1
   458
					type = S_BOOLEAN;
yann@1
   459
			}
yann@1
   460
			switch (type) {
yann@1
   461
			case S_BOOLEAN:
yann@1
   462
			case S_TRISTATE:
yann@1
   463
				switch (sym_get_tristate_value(sym)) {
yann@1
   464
				case no:
yann@1
   465
					fprintf(out, "# CT_%s is not set\n", sym->name);
yann@1
   466
					break;
yann@1
   467
				case mod:
yann@1
   468
					fprintf(out, "CT_%s=m\n", sym->name);
yann@1
   469
					break;
yann@1
   470
				case yes:
yann@1
   471
					fprintf(out, "CT_%s=y\n", sym->name);
yann@1
   472
					break;
yann@1
   473
				}
yann@1
   474
				break;
yann@1
   475
			case S_STRING:
yann@1
   476
				str = sym_get_string_value(sym);
yann@1
   477
				fprintf(out, "CT_%s=\"", sym->name);
yann@1
   478
				while (1) {
yann@1
   479
					l = strcspn(str, "\"\\");
yann@1
   480
					if (l) {
yann@1
   481
						fwrite(str, l, 1, out);
yann@1
   482
						str += l;
yann@1
   483
					}
yann@1
   484
					if (!*str)
yann@1
   485
						break;
yann@1
   486
					fprintf(out, "\\%c", *str++);
yann@1
   487
				}
yann@1
   488
				fputs("\"\n", out);
yann@1
   489
				break;
yann@1
   490
			case S_HEX:
yann@1
   491
				str = sym_get_string_value(sym);
yann@1
   492
				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
yann@39
   493
					fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   494
					break;
yann@1
   495
				}
yann@1
   496
			case S_INT:
yann@1
   497
				str = sym_get_string_value(sym);
yann@39
   498
				fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   499
				break;
yann@1
   500
			}
yann@1
   501
		}
yann@1
   502
yann@1
   503
	next:
yann@39
   504
		if (menu->list) {
yann@39
   505
			menu = menu->list;
yann@39
   506
			continue;
yann@39
   507
		}
yann@39
   508
		if (menu->next)
yann@39
   509
			menu = menu->next;
yann@39
   510
		else while ((menu = menu->parent)) {
yann@39
   511
			if (menu->next) {
yann@39
   512
				menu = menu->next;
yann@39
   513
				break;
yann@1
   514
			}
yann@39
   515
		}
yann@1
   516
	}
yann@1
   517
	fclose(out);
yann@1
   518
yann@1
   519
	if (*tmpname) {
yann@1
   520
		strcat(dirname, basename);
yann@1
   521
		strcat(dirname, ".old");
yann@1
   522
		rename(newname, dirname);
yann@1
   523
		if (rename(tmpname, newname))
yann@1
   524
			return 1;
yann@1
   525
	}
yann@1
   526
yann@1
   527
	printf(_("#\n"
yann@1
   528
		 "# configuration written to %s\n"
yann@1
   529
		 "#\n"), newname);
yann@1
   530
yann@39
   531
	sym_set_change_count(0);
yann@1
   532
yann@1
   533
	return 0;
yann@1
   534
}
yann@1
   535
yann@1
   536
int conf_split_config(void)
yann@1
   537
{
yann@1
   538
	char *name, path[128];
yann@1
   539
	char *s, *d, c;
yann@1
   540
	struct symbol *sym;
yann@1
   541
	struct stat sb;
yann@1
   542
	int res, i, fd;
yann@1
   543
yann@1
   544
	name = getenv("KCONFIG_AUTOCONFIG");
yann@1
   545
	if (!name)
yann@1
   546
		name = "include/config/auto.conf";
yann@1
   547
	conf_read_simple(name, S_DEF_AUTO);
yann@1
   548
yann@1
   549
	if (chdir("include/config"))
yann@1
   550
		return 1;
yann@1
   551
yann@1
   552
	res = 0;
yann@1
   553
	for_all_symbols(i, sym) {
yann@1
   554
		sym_calc_value(sym);
yann@1
   555
		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
yann@1
   556
			continue;
yann@1
   557
		if (sym->flags & SYMBOL_WRITE) {
yann@1
   558
			if (sym->flags & SYMBOL_DEF_AUTO) {
yann@1
   559
				/*
yann@1
   560
				 * symbol has old and new value,
yann@1
   561
				 * so compare them...
yann@1
   562
				 */
yann@1
   563
				switch (sym->type) {
yann@1
   564
				case S_BOOLEAN:
yann@1
   565
				case S_TRISTATE:
yann@1
   566
					if (sym_get_tristate_value(sym) ==
yann@1
   567
					    sym->def[S_DEF_AUTO].tri)
yann@1
   568
						continue;
yann@1
   569
					break;
yann@1
   570
				case S_STRING:
yann@1
   571
				case S_HEX:
yann@1
   572
				case S_INT:
yann@1
   573
					if (!strcmp(sym_get_string_value(sym),
yann@1
   574
						    sym->def[S_DEF_AUTO].val))
yann@1
   575
						continue;
yann@1
   576
					break;
yann@1
   577
				default:
yann@1
   578
					break;
yann@1
   579
				}
yann@1
   580
			} else {
yann@1
   581
				/*
yann@1
   582
				 * If there is no old value, only 'no' (unset)
yann@1
   583
				 * is allowed as new value.
yann@1
   584
				 */
yann@1
   585
				switch (sym->type) {
yann@1
   586
				case S_BOOLEAN:
yann@1
   587
				case S_TRISTATE:
yann@1
   588
					if (sym_get_tristate_value(sym) == no)
yann@1
   589
						continue;
yann@1
   590
					break;
yann@1
   591
				default:
yann@1
   592
					break;
yann@1
   593
				}
yann@1
   594
			}
yann@1
   595
		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
yann@1
   596
			/* There is neither an old nor a new value. */
yann@1
   597
			continue;
yann@1
   598
		/* else
yann@1
   599
		 *	There is an old value, but no new value ('no' (unset)
yann@1
   600
		 *	isn't saved in auto.conf, so the old value is always
yann@1
   601
		 *	different from 'no').
yann@1
   602
		 */
yann@1
   603
yann@1
   604
		/* Replace all '_' and append ".h" */
yann@1
   605
		s = sym->name;
yann@1
   606
		d = path;
yann@1
   607
		while ((c = *s++)) {
yann@1
   608
			c = tolower(c);
yann@1
   609
			*d++ = (c == '_') ? '/' : c;
yann@1
   610
		}
yann@1
   611
		strcpy(d, ".h");
yann@1
   612
yann@1
   613
		/* Assume directory path already exists. */
yann@1
   614
		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
yann@1
   615
		if (fd == -1) {
yann@1
   616
			if (errno != ENOENT) {
yann@1
   617
				res = 1;
yann@1
   618
				break;
yann@1
   619
			}
yann@1
   620
			/*
yann@1
   621
			 * Create directory components,
yann@1
   622
			 * unless they exist already.
yann@1
   623
			 */
yann@1
   624
			d = path;
yann@1
   625
			while ((d = strchr(d, '/'))) {
yann@1
   626
				*d = 0;
yann@1
   627
				if (stat(path, &sb) && mkdir(path, 0755)) {
yann@1
   628
					res = 1;
yann@1
   629
					goto out;
yann@1
   630
				}
yann@1
   631
				*d++ = '/';
yann@1
   632
			}
yann@1
   633
			/* Try it again. */
yann@1
   634
			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
yann@1
   635
			if (fd == -1) {
yann@1
   636
				res = 1;
yann@1
   637
				break;
yann@1
   638
			}
yann@1
   639
		}
yann@1
   640
		close(fd);
yann@1
   641
	}
yann@1
   642
out:
yann@1
   643
	if (chdir("../.."))
yann@1
   644
		return 1;
yann@1
   645
yann@1
   646
	return res;
yann@1
   647
}
yann@1
   648
yann@1
   649
int conf_write_autoconf(void)
yann@1
   650
{
yann@1
   651
	struct symbol *sym;
yann@1
   652
	const char *str;
yann@1
   653
	char *name;
yann@1
   654
	FILE *out, *out_h;
yann@1
   655
	time_t now;
yann@1
   656
	int i, l;
yann@1
   657
yann@1
   658
	sym_clear_all_valid();
yann@1
   659
yann@1
   660
	file_write_dep("include/config/auto.conf.cmd");
yann@1
   661
yann@1
   662
	if (conf_split_config())
yann@1
   663
		return 1;
yann@1
   664
yann@1
   665
	out = fopen(".tmpconfig", "w");
yann@1
   666
	if (!out)
yann@1
   667
		return 1;
yann@1
   668
yann@1
   669
	out_h = fopen(".tmpconfig.h", "w");
yann@1
   670
	if (!out_h) {
yann@1
   671
		fclose(out);
yann@1
   672
		return 1;
yann@1
   673
	}
yann@1
   674
yann@1
   675
	sym = sym_lookup("PROJECTVERSION", 0);
yann@1
   676
	sym_calc_value(sym);
yann@1
   677
	time(&now);
yann@1
   678
	fprintf(out, "#\n"
yann@1
   679
		     "# Automatically generated make config: don't edit\n"
yann@1
   680
		     "# "PROJECT_NAME" version: %s\n"
yann@1
   681
		     "# %s"
yann@1
   682
		     "#\n",
yann@1
   683
		     sym_get_string_value(sym), ctime(&now));
yann@1
   684
	fprintf(out_h, "/*\n"
yann@1
   685
		       " * Automatically generated C config: don't edit\n"
yann@1
   686
		       " * "PROJECT_NAME" version: %s\n"
yann@1
   687
		       " * %s"
yann@1
   688
		       " */\n"
yann@1
   689
		       "#define AUTOCONF_INCLUDED\n",
yann@1
   690
		       sym_get_string_value(sym), ctime(&now));
yann@1
   691
yann@1
   692
	for_all_symbols(i, sym) {
yann@1
   693
		sym_calc_value(sym);
yann@1
   694
		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
yann@1
   695
			continue;
yann@1
   696
		switch (sym->type) {
yann@1
   697
		case S_BOOLEAN:
yann@1
   698
		case S_TRISTATE:
yann@1
   699
			switch (sym_get_tristate_value(sym)) {
yann@1
   700
			case no:
yann@1
   701
				break;
yann@1
   702
			case mod:
yann@1
   703
				fprintf(out, "CT_%s=m\n", sym->name);
yann@1
   704
				fprintf(out_h, "#define CT_%s_MODULE 1\n", sym->name);
yann@1
   705
				break;
yann@1
   706
			case yes:
yann@1
   707
				fprintf(out, "CT_%s=y\n", sym->name);
yann@1
   708
				fprintf(out_h, "#define CT_%s 1\n", sym->name);
yann@1
   709
				break;
yann@1
   710
			}
yann@1
   711
			break;
yann@1
   712
		case S_STRING:
yann@1
   713
			str = sym_get_string_value(sym);
yann@1
   714
			fprintf(out, "CT_%s=\"", sym->name);
yann@1
   715
			fprintf(out_h, "#define CT_%s \"", sym->name);
yann@1
   716
			while (1) {
yann@1
   717
				l = strcspn(str, "\"\\");
yann@1
   718
				if (l) {
yann@1
   719
					fwrite(str, l, 1, out);
yann@1
   720
					fwrite(str, l, 1, out_h);
yann@1
   721
					str += l;
yann@1
   722
				}
yann@1
   723
				if (!*str)
yann@1
   724
					break;
yann@1
   725
				fprintf(out, "\\%c", *str);
yann@1
   726
				fprintf(out_h, "\\%c", *str);
yann@1
   727
				str++;
yann@1
   728
			}
yann@1
   729
			fputs("\"\n", out);
yann@1
   730
			fputs("\"\n", out_h);
yann@1
   731
			break;
yann@1
   732
		case S_HEX:
yann@1
   733
			str = sym_get_string_value(sym);
yann@1
   734
			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
yann@1
   735
				fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   736
				fprintf(out_h, "#define CT_%s 0x%s\n", sym->name, str);
yann@1
   737
				break;
yann@1
   738
			}
yann@1
   739
		case S_INT:
yann@1
   740
			str = sym_get_string_value(sym);
yann@1
   741
			fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   742
			fprintf(out_h, "#define CT_%s %s\n", sym->name, str);
yann@1
   743
			break;
yann@1
   744
		default:
yann@1
   745
			break;
yann@1
   746
		}
yann@1
   747
	}
yann@1
   748
	fclose(out);
yann@1
   749
	fclose(out_h);
yann@1
   750
yann@1
   751
	name = getenv("KCONFIG_AUTOHEADER");
yann@1
   752
	if (!name)
yann@1
   753
		name = "include/linux/autoconf.h";
yann@1
   754
	if (rename(".tmpconfig.h", name))
yann@1
   755
		return 1;
yann@1
   756
	name = getenv("KCONFIG_AUTOCONFIG");
yann@1
   757
	if (!name)
yann@1
   758
		name = "include/config/auto.conf";
yann@1
   759
	/*
yann@1
   760
	 * This must be the last step, kbuild has a dependency on auto.conf
yann@1
   761
	 * and this marks the successful completion of the previous steps.
yann@1
   762
	 */
yann@1
   763
	if (rename(".tmpconfig", name))
yann@1
   764
		return 1;
yann@1
   765
yann@1
   766
	return 0;
yann@1
   767
}
yann@39
   768
yann@39
   769
static int sym_change_count;
yann@39
   770
static void (*conf_changed_callback)(void);
yann@39
   771
yann@39
   772
void sym_set_change_count(int count)
yann@39
   773
{
yann@39
   774
	int _sym_change_count = sym_change_count;
yann@39
   775
	sym_change_count = count;
yann@39
   776
	if (conf_changed_callback &&
yann@39
   777
	    (bool)_sym_change_count != (bool)count)
yann@39
   778
		conf_changed_callback();
yann@39
   779
}
yann@39
   780
yann@39
   781
void sym_add_change_count(int count)
yann@39
   782
{
yann@39
   783
	sym_set_change_count(count + sym_change_count);
yann@39
   784
}
yann@39
   785
yann@39
   786
bool conf_get_changed(void)
yann@39
   787
{
yann@39
   788
	return sym_change_count;
yann@39
   789
}
yann@39
   790
yann@39
   791
void conf_set_changed_callback(void (*fn)(void))
yann@39
   792
{
yann@39
   793
	conf_changed_callback = fn;
yann@39
   794
}