kconfig/confdata.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Thu Sep 11 09:01:48 2008 +0000 (2008-09-11)
changeset 848 5b3785e0d41d
parent 39 af42eec9d383
child 943 1cca90ce0481
permissions -rw-r--r--
Fix auto-completion for updaetools.

/trunk/ct-ng.comp | 2 1 1 0 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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@39
   527
	sym_set_change_count(0);
yann@1
   528
yann@1
   529
	return 0;
yann@1
   530
}
yann@1
   531
yann@1
   532
int conf_split_config(void)
yann@1
   533
{
yann@1
   534
	char *name, path[128];
yann@1
   535
	char *s, *d, c;
yann@1
   536
	struct symbol *sym;
yann@1
   537
	struct stat sb;
yann@1
   538
	int res, i, fd;
yann@1
   539
yann@1
   540
	name = getenv("KCONFIG_AUTOCONFIG");
yann@1
   541
	if (!name)
yann@1
   542
		name = "include/config/auto.conf";
yann@1
   543
	conf_read_simple(name, S_DEF_AUTO);
yann@1
   544
yann@1
   545
	if (chdir("include/config"))
yann@1
   546
		return 1;
yann@1
   547
yann@1
   548
	res = 0;
yann@1
   549
	for_all_symbols(i, sym) {
yann@1
   550
		sym_calc_value(sym);
yann@1
   551
		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
yann@1
   552
			continue;
yann@1
   553
		if (sym->flags & SYMBOL_WRITE) {
yann@1
   554
			if (sym->flags & SYMBOL_DEF_AUTO) {
yann@1
   555
				/*
yann@1
   556
				 * symbol has old and new value,
yann@1
   557
				 * so compare them...
yann@1
   558
				 */
yann@1
   559
				switch (sym->type) {
yann@1
   560
				case S_BOOLEAN:
yann@1
   561
				case S_TRISTATE:
yann@1
   562
					if (sym_get_tristate_value(sym) ==
yann@1
   563
					    sym->def[S_DEF_AUTO].tri)
yann@1
   564
						continue;
yann@1
   565
					break;
yann@1
   566
				case S_STRING:
yann@1
   567
				case S_HEX:
yann@1
   568
				case S_INT:
yann@1
   569
					if (!strcmp(sym_get_string_value(sym),
yann@1
   570
						    sym->def[S_DEF_AUTO].val))
yann@1
   571
						continue;
yann@1
   572
					break;
yann@1
   573
				default:
yann@1
   574
					break;
yann@1
   575
				}
yann@1
   576
			} else {
yann@1
   577
				/*
yann@1
   578
				 * If there is no old value, only 'no' (unset)
yann@1
   579
				 * is allowed as new value.
yann@1
   580
				 */
yann@1
   581
				switch (sym->type) {
yann@1
   582
				case S_BOOLEAN:
yann@1
   583
				case S_TRISTATE:
yann@1
   584
					if (sym_get_tristate_value(sym) == no)
yann@1
   585
						continue;
yann@1
   586
					break;
yann@1
   587
				default:
yann@1
   588
					break;
yann@1
   589
				}
yann@1
   590
			}
yann@1
   591
		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
yann@1
   592
			/* There is neither an old nor a new value. */
yann@1
   593
			continue;
yann@1
   594
		/* else
yann@1
   595
		 *	There is an old value, but no new value ('no' (unset)
yann@1
   596
		 *	isn't saved in auto.conf, so the old value is always
yann@1
   597
		 *	different from 'no').
yann@1
   598
		 */
yann@1
   599
yann@1
   600
		/* Replace all '_' and append ".h" */
yann@1
   601
		s = sym->name;
yann@1
   602
		d = path;
yann@1
   603
		while ((c = *s++)) {
yann@1
   604
			c = tolower(c);
yann@1
   605
			*d++ = (c == '_') ? '/' : c;
yann@1
   606
		}
yann@1
   607
		strcpy(d, ".h");
yann@1
   608
yann@1
   609
		/* Assume directory path already exists. */
yann@1
   610
		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
yann@1
   611
		if (fd == -1) {
yann@1
   612
			if (errno != ENOENT) {
yann@1
   613
				res = 1;
yann@1
   614
				break;
yann@1
   615
			}
yann@1
   616
			/*
yann@1
   617
			 * Create directory components,
yann@1
   618
			 * unless they exist already.
yann@1
   619
			 */
yann@1
   620
			d = path;
yann@1
   621
			while ((d = strchr(d, '/'))) {
yann@1
   622
				*d = 0;
yann@1
   623
				if (stat(path, &sb) && mkdir(path, 0755)) {
yann@1
   624
					res = 1;
yann@1
   625
					goto out;
yann@1
   626
				}
yann@1
   627
				*d++ = '/';
yann@1
   628
			}
yann@1
   629
			/* Try it again. */
yann@1
   630
			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
yann@1
   631
			if (fd == -1) {
yann@1
   632
				res = 1;
yann@1
   633
				break;
yann@1
   634
			}
yann@1
   635
		}
yann@1
   636
		close(fd);
yann@1
   637
	}
yann@1
   638
out:
yann@1
   639
	if (chdir("../.."))
yann@1
   640
		return 1;
yann@1
   641
yann@1
   642
	return res;
yann@1
   643
}
yann@1
   644
yann@1
   645
int conf_write_autoconf(void)
yann@1
   646
{
yann@1
   647
	struct symbol *sym;
yann@1
   648
	const char *str;
yann@1
   649
	char *name;
yann@1
   650
	FILE *out, *out_h;
yann@1
   651
	time_t now;
yann@1
   652
	int i, l;
yann@1
   653
yann@1
   654
	sym_clear_all_valid();
yann@1
   655
yann@1
   656
	file_write_dep("include/config/auto.conf.cmd");
yann@1
   657
yann@1
   658
	if (conf_split_config())
yann@1
   659
		return 1;
yann@1
   660
yann@1
   661
	out = fopen(".tmpconfig", "w");
yann@1
   662
	if (!out)
yann@1
   663
		return 1;
yann@1
   664
yann@1
   665
	out_h = fopen(".tmpconfig.h", "w");
yann@1
   666
	if (!out_h) {
yann@1
   667
		fclose(out);
yann@1
   668
		return 1;
yann@1
   669
	}
yann@1
   670
yann@1
   671
	sym = sym_lookup("PROJECTVERSION", 0);
yann@1
   672
	sym_calc_value(sym);
yann@1
   673
	time(&now);
yann@1
   674
	fprintf(out, "#\n"
yann@1
   675
		     "# Automatically generated make config: don't edit\n"
yann@1
   676
		     "# "PROJECT_NAME" version: %s\n"
yann@1
   677
		     "# %s"
yann@1
   678
		     "#\n",
yann@1
   679
		     sym_get_string_value(sym), ctime(&now));
yann@1
   680
	fprintf(out_h, "/*\n"
yann@1
   681
		       " * Automatically generated C config: don't edit\n"
yann@1
   682
		       " * "PROJECT_NAME" version: %s\n"
yann@1
   683
		       " * %s"
yann@1
   684
		       " */\n"
yann@1
   685
		       "#define AUTOCONF_INCLUDED\n",
yann@1
   686
		       sym_get_string_value(sym), ctime(&now));
yann@1
   687
yann@1
   688
	for_all_symbols(i, sym) {
yann@1
   689
		sym_calc_value(sym);
yann@1
   690
		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
yann@1
   691
			continue;
yann@1
   692
		switch (sym->type) {
yann@1
   693
		case S_BOOLEAN:
yann@1
   694
		case S_TRISTATE:
yann@1
   695
			switch (sym_get_tristate_value(sym)) {
yann@1
   696
			case no:
yann@1
   697
				break;
yann@1
   698
			case mod:
yann@1
   699
				fprintf(out, "CT_%s=m\n", sym->name);
yann@1
   700
				fprintf(out_h, "#define CT_%s_MODULE 1\n", sym->name);
yann@1
   701
				break;
yann@1
   702
			case yes:
yann@1
   703
				fprintf(out, "CT_%s=y\n", sym->name);
yann@1
   704
				fprintf(out_h, "#define CT_%s 1\n", sym->name);
yann@1
   705
				break;
yann@1
   706
			}
yann@1
   707
			break;
yann@1
   708
		case S_STRING:
yann@1
   709
			str = sym_get_string_value(sym);
yann@1
   710
			fprintf(out, "CT_%s=\"", sym->name);
yann@1
   711
			fprintf(out_h, "#define CT_%s \"", sym->name);
yann@1
   712
			while (1) {
yann@1
   713
				l = strcspn(str, "\"\\");
yann@1
   714
				if (l) {
yann@1
   715
					fwrite(str, l, 1, out);
yann@1
   716
					fwrite(str, l, 1, out_h);
yann@1
   717
					str += l;
yann@1
   718
				}
yann@1
   719
				if (!*str)
yann@1
   720
					break;
yann@1
   721
				fprintf(out, "\\%c", *str);
yann@1
   722
				fprintf(out_h, "\\%c", *str);
yann@1
   723
				str++;
yann@1
   724
			}
yann@1
   725
			fputs("\"\n", out);
yann@1
   726
			fputs("\"\n", out_h);
yann@1
   727
			break;
yann@1
   728
		case S_HEX:
yann@1
   729
			str = sym_get_string_value(sym);
yann@1
   730
			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
yann@1
   731
				fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   732
				fprintf(out_h, "#define CT_%s 0x%s\n", sym->name, str);
yann@1
   733
				break;
yann@1
   734
			}
yann@1
   735
		case S_INT:
yann@1
   736
			str = sym_get_string_value(sym);
yann@1
   737
			fprintf(out, "CT_%s=%s\n", sym->name, str);
yann@1
   738
			fprintf(out_h, "#define CT_%s %s\n", sym->name, str);
yann@1
   739
			break;
yann@1
   740
		default:
yann@1
   741
			break;
yann@1
   742
		}
yann@1
   743
	}
yann@1
   744
	fclose(out);
yann@1
   745
	fclose(out_h);
yann@1
   746
yann@1
   747
	name = getenv("KCONFIG_AUTOHEADER");
yann@1
   748
	if (!name)
yann@1
   749
		name = "include/linux/autoconf.h";
yann@1
   750
	if (rename(".tmpconfig.h", name))
yann@1
   751
		return 1;
yann@1
   752
	name = getenv("KCONFIG_AUTOCONFIG");
yann@1
   753
	if (!name)
yann@1
   754
		name = "include/config/auto.conf";
yann@1
   755
	/*
yann@1
   756
	 * This must be the last step, kbuild has a dependency on auto.conf
yann@1
   757
	 * and this marks the successful completion of the previous steps.
yann@1
   758
	 */
yann@1
   759
	if (rename(".tmpconfig", name))
yann@1
   760
		return 1;
yann@1
   761
yann@1
   762
	return 0;
yann@1
   763
}
yann@39
   764
yann@39
   765
static int sym_change_count;
yann@39
   766
static void (*conf_changed_callback)(void);
yann@39
   767
yann@39
   768
void sym_set_change_count(int count)
yann@39
   769
{
yann@39
   770
	int _sym_change_count = sym_change_count;
yann@39
   771
	sym_change_count = count;
yann@39
   772
	if (conf_changed_callback &&
yann@39
   773
	    (bool)_sym_change_count != (bool)count)
yann@39
   774
		conf_changed_callback();
yann@39
   775
}
yann@39
   776
yann@39
   777
void sym_add_change_count(int count)
yann@39
   778
{
yann@39
   779
	sym_set_change_count(count + sym_change_count);
yann@39
   780
}
yann@39
   781
yann@39
   782
bool conf_get_changed(void)
yann@39
   783
{
yann@39
   784
	return sym_change_count;
yann@39
   785
}
yann@39
   786
yann@39
   787
void conf_set_changed_callback(void (*fn)(void))
yann@39
   788
{
yann@39
   789
	conf_changed_callback = fn;
yann@39
   790
}