kconfig/confdata.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 94 f32c4f663805
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).
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
}