xref: /linux-6.15/scripts/kconfig/confdata.c (revision 226ac19c)
10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Copyright (C) 2002 Roman Zippel <[email protected]>
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
667424f61SMasahiro Yamada #include <sys/mman.h>
71da177e4SLinus Torvalds #include <sys/stat.h>
878cb0907SBoris Kolpackov #include <sys/types.h>
91da177e4SLinus Torvalds #include <ctype.h>
1094bedecaSArnaud Lacombe #include <errno.h>
112e3646e5SRoman Zippel #include <fcntl.h>
12558e78e3SMasahiro Yamada #include <limits.h>
1310a4b277SArnaud Lacombe #include <stdarg.h>
146ce45a91SMasahiro Yamada #include <stdbool.h>
151da177e4SLinus Torvalds #include <stdio.h>
161da177e4SLinus Torvalds #include <stdlib.h>
171da177e4SLinus Torvalds #include <string.h>
181da177e4SLinus Torvalds #include <time.h>
191da177e4SLinus Torvalds #include <unistd.h>
201da177e4SLinus Torvalds 
21a9d83d74SMasahiro Yamada #include <xalloc.h>
2291b69454SMasahiro Yamada #include "internal.h"
231da177e4SLinus Torvalds #include "lkc.h"
241da177e4SLinus Torvalds 
25526396b7SMasahiro Yamada struct gstr autoconf_cmd;
26526396b7SMasahiro Yamada 
270608182aSMasahiro Yamada /* return true if 'path' exists, false otherwise */
is_present(const char * path)280608182aSMasahiro Yamada static bool is_present(const char *path)
290608182aSMasahiro Yamada {
300608182aSMasahiro Yamada 	struct stat st;
310608182aSMasahiro Yamada 
320608182aSMasahiro Yamada 	return !stat(path, &st);
330608182aSMasahiro Yamada }
340608182aSMasahiro Yamada 
350608182aSMasahiro Yamada /* return true if 'path' exists and it is a directory, false otherwise */
is_dir(const char * path)360608182aSMasahiro Yamada static bool is_dir(const char *path)
370608182aSMasahiro Yamada {
380608182aSMasahiro Yamada 	struct stat st;
390608182aSMasahiro Yamada 
400608182aSMasahiro Yamada 	if (stat(path, &st))
41a69b191fSYang Li 		return false;
420608182aSMasahiro Yamada 
430608182aSMasahiro Yamada 	return S_ISDIR(st.st_mode);
440608182aSMasahiro Yamada }
450608182aSMasahiro Yamada 
4667424f61SMasahiro Yamada /* return true if the given two files are the same, false otherwise */
is_same(const char * file1,const char * file2)4767424f61SMasahiro Yamada static bool is_same(const char *file1, const char *file2)
4867424f61SMasahiro Yamada {
4967424f61SMasahiro Yamada 	int fd1, fd2;
5067424f61SMasahiro Yamada 	struct stat st1, st2;
5167424f61SMasahiro Yamada 	void *map1, *map2;
5267424f61SMasahiro Yamada 	bool ret = false;
5367424f61SMasahiro Yamada 
5467424f61SMasahiro Yamada 	fd1 = open(file1, O_RDONLY);
5567424f61SMasahiro Yamada 	if (fd1 < 0)
5667424f61SMasahiro Yamada 		return ret;
5767424f61SMasahiro Yamada 
5867424f61SMasahiro Yamada 	fd2 = open(file2, O_RDONLY);
5967424f61SMasahiro Yamada 	if (fd2 < 0)
6067424f61SMasahiro Yamada 		goto close1;
6167424f61SMasahiro Yamada 
6267424f61SMasahiro Yamada 	ret = fstat(fd1, &st1);
6367424f61SMasahiro Yamada 	if (ret)
6467424f61SMasahiro Yamada 		goto close2;
6567424f61SMasahiro Yamada 	ret = fstat(fd2, &st2);
6667424f61SMasahiro Yamada 	if (ret)
6767424f61SMasahiro Yamada 		goto close2;
6867424f61SMasahiro Yamada 
6967424f61SMasahiro Yamada 	if (st1.st_size != st2.st_size)
7067424f61SMasahiro Yamada 		goto close2;
7167424f61SMasahiro Yamada 
7267424f61SMasahiro Yamada 	map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
7367424f61SMasahiro Yamada 	if (map1 == MAP_FAILED)
7467424f61SMasahiro Yamada 		goto close2;
7567424f61SMasahiro Yamada 
7667424f61SMasahiro Yamada 	map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
7767424f61SMasahiro Yamada 	if (map2 == MAP_FAILED)
7867424f61SMasahiro Yamada 		goto close2;
7967424f61SMasahiro Yamada 
8067424f61SMasahiro Yamada 	if (bcmp(map1, map2, st1.st_size))
8167424f61SMasahiro Yamada 		goto close2;
8267424f61SMasahiro Yamada 
8367424f61SMasahiro Yamada 	ret = true;
8467424f61SMasahiro Yamada close2:
8567424f61SMasahiro Yamada 	close(fd2);
8667424f61SMasahiro Yamada close1:
8767424f61SMasahiro Yamada 	close(fd1);
8867424f61SMasahiro Yamada 
8967424f61SMasahiro Yamada 	return ret;
9067424f61SMasahiro Yamada }
9167424f61SMasahiro Yamada 
920608182aSMasahiro Yamada /*
930608182aSMasahiro Yamada  * Create the parent directory of the given path.
940608182aSMasahiro Yamada  *
950608182aSMasahiro Yamada  * For example, if 'include/config/auto.conf' is given, create 'include/config'.
960608182aSMasahiro Yamada  */
make_parent_dir(const char * path)970608182aSMasahiro Yamada static int make_parent_dir(const char *path)
980608182aSMasahiro Yamada {
990608182aSMasahiro Yamada 	char tmp[PATH_MAX + 1];
1000608182aSMasahiro Yamada 	char *p;
1010608182aSMasahiro Yamada 
1020608182aSMasahiro Yamada 	strncpy(tmp, path, sizeof(tmp));
1030608182aSMasahiro Yamada 	tmp[sizeof(tmp) - 1] = 0;
1040608182aSMasahiro Yamada 
1050608182aSMasahiro Yamada 	/* Remove the base name. Just return if nothing is left */
1060608182aSMasahiro Yamada 	p = strrchr(tmp, '/');
1070608182aSMasahiro Yamada 	if (!p)
1080608182aSMasahiro Yamada 		return 0;
1090608182aSMasahiro Yamada 	*(p + 1) = 0;
1100608182aSMasahiro Yamada 
1110608182aSMasahiro Yamada 	/* Just in case it is an absolute path */
1120608182aSMasahiro Yamada 	p = tmp;
1130608182aSMasahiro Yamada 	while (*p == '/')
1140608182aSMasahiro Yamada 		p++;
1150608182aSMasahiro Yamada 
1160608182aSMasahiro Yamada 	while ((p = strchr(p, '/'))) {
1170608182aSMasahiro Yamada 		*p = 0;
1180608182aSMasahiro Yamada 
1190608182aSMasahiro Yamada 		/* skip if the directory exists */
1200608182aSMasahiro Yamada 		if (!is_dir(tmp) && mkdir(tmp, 0755))
1210608182aSMasahiro Yamada 			return -1;
1220608182aSMasahiro Yamada 
1230608182aSMasahiro Yamada 		*p = '/';
1240608182aSMasahiro Yamada 		while (*p == '/')
1250608182aSMasahiro Yamada 			p++;
1260608182aSMasahiro Yamada 	}
1270608182aSMasahiro Yamada 
1280608182aSMasahiro Yamada 	return 0;
1290608182aSMasahiro Yamada }
1300608182aSMasahiro Yamada 
1311508fec8SMasahiro Yamada static char depfile_path[PATH_MAX];
1321508fec8SMasahiro Yamada static size_t depfile_prefix_len;
1331508fec8SMasahiro Yamada 
1341508fec8SMasahiro Yamada /* touch depfile for symbol 'name' */
conf_touch_dep(const char * name)1351508fec8SMasahiro Yamada static int conf_touch_dep(const char *name)
1361508fec8SMasahiro Yamada {
137fee762d6SMasahiro Yamada 	int fd;
1381508fec8SMasahiro Yamada 
1390e0345b7SAlexey Dobriyan 	/* check overflow: prefix + name + '\0' must fit in buffer. */
1400e0345b7SAlexey Dobriyan 	if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
1411508fec8SMasahiro Yamada 		return -1;
1421508fec8SMasahiro Yamada 
143fee762d6SMasahiro Yamada 	strcpy(depfile_path + depfile_prefix_len, name);
1441508fec8SMasahiro Yamada 
1451508fec8SMasahiro Yamada 	fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1461508fec8SMasahiro Yamada 	if (fd == -1)
1471508fec8SMasahiro Yamada 		return -1;
1481508fec8SMasahiro Yamada 	close(fd);
1491508fec8SMasahiro Yamada 
1501508fec8SMasahiro Yamada 	return 0;
1511508fec8SMasahiro Yamada }
1521508fec8SMasahiro Yamada 
153c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...)
154c1a0f5e3SRoman Zippel 	__attribute__ ((format (printf, 1, 2)));
155c1a0f5e3SRoman Zippel 
15642368c37SMichal Marek static void conf_message(const char *fmt, ...)
15742368c37SMichal Marek 	__attribute__ ((format (printf, 1, 2)));
15842368c37SMichal Marek 
159c1a0f5e3SRoman Zippel static const char *conf_filename;
16084dd95d4SMasahiro Yamada static int conf_lineno, conf_warnings;
161c1a0f5e3SRoman Zippel 
conf_errors(void)16215d3f766SSergey Senozhatsky bool conf_errors(void)
16315d3f766SSergey Senozhatsky {
16415d3f766SSergey Senozhatsky 	if (conf_warnings)
16515d3f766SSergey Senozhatsky 		return getenv("KCONFIG_WERROR");
16615d3f766SSergey Senozhatsky 	return false;
16715d3f766SSergey Senozhatsky }
16815d3f766SSergey Senozhatsky 
conf_warning(const char * fmt,...)169c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...)
170c1a0f5e3SRoman Zippel {
171c1a0f5e3SRoman Zippel 	va_list ap;
172c1a0f5e3SRoman Zippel 	va_start(ap, fmt);
173c1a0f5e3SRoman Zippel 	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
174c1a0f5e3SRoman Zippel 	vfprintf(stderr, fmt, ap);
175c1a0f5e3SRoman Zippel 	fprintf(stderr, "\n");
176c1a0f5e3SRoman Zippel 	va_end(ap);
177c1a0f5e3SRoman Zippel 	conf_warnings++;
178c1a0f5e3SRoman Zippel }
179c1a0f5e3SRoman Zippel 
conf_default_message_callback(const char * s)1805accd7f3SMasahiro Yamada static void conf_default_message_callback(const char *s)
18142368c37SMichal Marek {
18242368c37SMichal Marek 	printf("#\n# ");
1835accd7f3SMasahiro Yamada 	printf("%s", s);
18442368c37SMichal Marek 	printf("\n#\n");
18542368c37SMichal Marek }
18642368c37SMichal Marek 
1875accd7f3SMasahiro Yamada static void (*conf_message_callback)(const char *s) =
18842368c37SMichal Marek 	conf_default_message_callback;
conf_set_message_callback(void (* fn)(const char * s))1895accd7f3SMasahiro Yamada void conf_set_message_callback(void (*fn)(const char *s))
19042368c37SMichal Marek {
19142368c37SMichal Marek 	conf_message_callback = fn;
19242368c37SMichal Marek }
19342368c37SMichal Marek 
conf_message(const char * fmt,...)19442368c37SMichal Marek static void conf_message(const char *fmt, ...)
19542368c37SMichal Marek {
19642368c37SMichal Marek 	va_list ap;
1975accd7f3SMasahiro Yamada 	char buf[4096];
1985accd7f3SMasahiro Yamada 
1995accd7f3SMasahiro Yamada 	if (!conf_message_callback)
2005accd7f3SMasahiro Yamada 		return;
20142368c37SMichal Marek 
20242368c37SMichal Marek 	va_start(ap, fmt);
2035accd7f3SMasahiro Yamada 
2045accd7f3SMasahiro Yamada 	vsnprintf(buf, sizeof(buf), fmt, ap);
2055accd7f3SMasahiro Yamada 	conf_message_callback(buf);
206b6a2ab2cSColin Ian King 	va_end(ap);
20742368c37SMichal Marek }
20842368c37SMichal Marek 
conf_get_configname(void)20914cdd3c4SRoman Zippel const char *conf_get_configname(void)
21014cdd3c4SRoman Zippel {
21114cdd3c4SRoman Zippel 	char *name = getenv("KCONFIG_CONFIG");
21214cdd3c4SRoman Zippel 
21314cdd3c4SRoman Zippel 	return name ? name : ".config";
21414cdd3c4SRoman Zippel }
21514cdd3c4SRoman Zippel 
conf_get_autoconfig_name(void)2169b9f5948SMasahiro Yamada static const char *conf_get_autoconfig_name(void)
21712122f62SMarkus Heidelberg {
21812122f62SMarkus Heidelberg 	char *name = getenv("KCONFIG_AUTOCONFIG");
21912122f62SMarkus Heidelberg 
22012122f62SMarkus Heidelberg 	return name ? name : "include/config/auto.conf";
22112122f62SMarkus Heidelberg }
22212122f62SMarkus Heidelberg 
conf_get_autoheader_name(void)2238499f2ddSMasahiro Yamada static const char *conf_get_autoheader_name(void)
2248499f2ddSMasahiro Yamada {
2258499f2ddSMasahiro Yamada 	char *name = getenv("KCONFIG_AUTOHEADER");
2268499f2ddSMasahiro Yamada 
2278499f2ddSMasahiro Yamada 	return name ? name : "include/generated/autoconf.h";
2288499f2ddSMasahiro Yamada }
2298499f2ddSMasahiro Yamada 
conf_get_rustccfg_name(void)2302f7ab126SMiguel Ojeda static const char *conf_get_rustccfg_name(void)
2312f7ab126SMiguel Ojeda {
2322f7ab126SMiguel Ojeda 	char *name = getenv("KCONFIG_RUSTCCFG");
2332f7ab126SMiguel Ojeda 
2342f7ab126SMiguel Ojeda 	return name ? name : "include/generated/rustc_cfg";
2352f7ab126SMiguel Ojeda }
2362f7ab126SMiguel Ojeda 
conf_set_sym_val(struct symbol * sym,int def,int def_flags,char * p)2379c900a9cSSam Ravnborg static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
2389c900a9cSSam Ravnborg {
2399c900a9cSSam Ravnborg 	char *p2;
2409c900a9cSSam Ravnborg 
2419c900a9cSSam Ravnborg 	switch (sym->type) {
2429c900a9cSSam Ravnborg 	case S_TRISTATE:
2439c900a9cSSam Ravnborg 		if (p[0] == 'm') {
2449c900a9cSSam Ravnborg 			sym->def[def].tri = mod;
2459c900a9cSSam Ravnborg 			sym->flags |= def_flags;
2469c900a9cSSam Ravnborg 			break;
2479c900a9cSSam Ravnborg 		}
248d8fc3200SArnaud Lacombe 		/* fall through */
2499c900a9cSSam Ravnborg 	case S_BOOLEAN:
2509c900a9cSSam Ravnborg 		if (p[0] == 'y') {
2519c900a9cSSam Ravnborg 			sym->def[def].tri = yes;
2529c900a9cSSam Ravnborg 			sym->flags |= def_flags;
2539c900a9cSSam Ravnborg 			break;
2549c900a9cSSam Ravnborg 		}
2559c900a9cSSam Ravnborg 		if (p[0] == 'n') {
2569c900a9cSSam Ravnborg 			sym->def[def].tri = no;
2579c900a9cSSam Ravnborg 			sym->flags |= def_flags;
2589c900a9cSSam Ravnborg 			break;
2599c900a9cSSam Ravnborg 		}
26004b19b77SYann E. MORIN 		if (def != S_DEF_AUTO)
26104b19b77SYann E. MORIN 			conf_warning("symbol value '%s' invalid for %s",
26204b19b77SYann E. MORIN 				     p, sym->name);
26375f1468bSArnaud Lacombe 		return 1;
2649c900a9cSSam Ravnborg 	case S_STRING:
265129ab0d2SMasahiro Yamada 		/* No escaping for S_DEF_AUTO (include/config/auto.conf) */
266129ab0d2SMasahiro Yamada 		if (def != S_DEF_AUTO) {
2679c900a9cSSam Ravnborg 			if (*p++ != '"')
2689c900a9cSSam Ravnborg 				break;
2699c900a9cSSam Ravnborg 			for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
2709c900a9cSSam Ravnborg 				if (*p2 == '"') {
2719c900a9cSSam Ravnborg 					*p2 = 0;
2729c900a9cSSam Ravnborg 					break;
2739c900a9cSSam Ravnborg 				}
2749c900a9cSSam Ravnborg 				memmove(p2, p2 + 1, strlen(p2));
2759c900a9cSSam Ravnborg 			}
2769c900a9cSSam Ravnborg 			if (!p2) {
2779c900a9cSSam Ravnborg 				conf_warning("invalid string found");
2789c900a9cSSam Ravnborg 				return 1;
2799c900a9cSSam Ravnborg 			}
280129ab0d2SMasahiro Yamada 		}
281d8fc3200SArnaud Lacombe 		/* fall through */
2829c900a9cSSam Ravnborg 	case S_INT:
2839c900a9cSSam Ravnborg 	case S_HEX:
2849c900a9cSSam Ravnborg 		if (sym_string_valid(sym, p)) {
285cd81fc82SMasahiro Yamada 			sym->def[def].val = xstrdup(p);
2869c900a9cSSam Ravnborg 			sym->flags |= def_flags;
2879c900a9cSSam Ravnborg 		} else {
28804b19b77SYann E. MORIN 			if (def != S_DEF_AUTO)
28904b19b77SYann E. MORIN 				conf_warning("symbol value '%s' invalid for %s",
29004b19b77SYann E. MORIN 					     p, sym->name);
2919c900a9cSSam Ravnborg 			return 1;
2929c900a9cSSam Ravnborg 		}
2939c900a9cSSam Ravnborg 		break;
2949c900a9cSSam Ravnborg 	default:
2959c900a9cSSam Ravnborg 		;
2969c900a9cSSam Ravnborg 	}
2979c900a9cSSam Ravnborg 	return 0;
2989c900a9cSSam Ravnborg }
2999c900a9cSSam Ravnborg 
3009925d6b7SMasahiro Yamada /* like getline(), but the newline character is stripped away */
getline_stripped(char ** lineptr,size_t * n,FILE * stream)3019925d6b7SMasahiro Yamada static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream)
3029925d6b7SMasahiro Yamada {
3039925d6b7SMasahiro Yamada 	ssize_t len;
3049925d6b7SMasahiro Yamada 
305aa8427fbSMasahiro Yamada 	len = getline(lineptr, n, stream);
3069925d6b7SMasahiro Yamada 
3079925d6b7SMasahiro Yamada 	if (len > 0 && (*lineptr)[len - 1] == '\n') {
3089925d6b7SMasahiro Yamada 		len--;
3099925d6b7SMasahiro Yamada 		(*lineptr)[len] = '\0';
3109925d6b7SMasahiro Yamada 
3119925d6b7SMasahiro Yamada 		if (len > 0 && (*lineptr)[len - 1] == '\r') {
3129925d6b7SMasahiro Yamada 			len--;
3139925d6b7SMasahiro Yamada 			(*lineptr)[len] = '\0';
3149925d6b7SMasahiro Yamada 		}
3159925d6b7SMasahiro Yamada 	}
3169925d6b7SMasahiro Yamada 
3179925d6b7SMasahiro Yamada 	return len;
3189925d6b7SMasahiro Yamada }
3199925d6b7SMasahiro Yamada 
conf_read_simple(const char * name,int def)320669bfad9SRoman Zippel int conf_read_simple(const char *name, int def)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	FILE *in = NULL;
3231a7a8c6fSCody Schafer 	char   *line = NULL;
3241a7a8c6fSCody Schafer 	size_t  line_asize = 0;
3259925d6b7SMasahiro Yamada 	char *p, *val;
3261da177e4SLinus Torvalds 	struct symbol *sym;
32791b69454SMasahiro Yamada 	int def_flags;
32815d3f766SSergey Senozhatsky 	const char *warn_unknown, *sym_name;
3291da177e4SLinus Torvalds 
3307cd34300SSergey Senozhatsky 	warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
3311da177e4SLinus Torvalds 	if (name) {
3321da177e4SLinus Torvalds 		in = zconf_fopen(name);
3331da177e4SLinus Torvalds 	} else {
334b75b0a81SMasahiro Yamada 		char *env;
335face4374SRoman Zippel 
33614cdd3c4SRoman Zippel 		name = conf_get_configname();
337ddc97cacSRoman Zippel 		in = zconf_fopen(name);
338ddc97cacSRoman Zippel 		if (in)
339ddc97cacSRoman Zippel 			goto load;
3405ee54659SMasahiro Yamada 		conf_set_changed(true);
341b75b0a81SMasahiro Yamada 
342b75b0a81SMasahiro Yamada 		env = getenv("KCONFIG_DEFCONFIG_LIST");
343b75b0a81SMasahiro Yamada 		if (!env)
344face4374SRoman Zippel 			return 1;
345face4374SRoman Zippel 
346b75b0a81SMasahiro Yamada 		while (1) {
347b75b0a81SMasahiro Yamada 			bool is_last;
348b75b0a81SMasahiro Yamada 
349b75b0a81SMasahiro Yamada 			while (isspace(*env))
350b75b0a81SMasahiro Yamada 				env++;
351b75b0a81SMasahiro Yamada 
352b75b0a81SMasahiro Yamada 			if (!*env)
353b75b0a81SMasahiro Yamada 				break;
354b75b0a81SMasahiro Yamada 
355b75b0a81SMasahiro Yamada 			p = env;
356b75b0a81SMasahiro Yamada 			while (*p && !isspace(*p))
357b75b0a81SMasahiro Yamada 				p++;
358b75b0a81SMasahiro Yamada 
359b75b0a81SMasahiro Yamada 			is_last = (*p == '\0');
360b75b0a81SMasahiro Yamada 
361b75b0a81SMasahiro Yamada 			*p = '\0';
362b75b0a81SMasahiro Yamada 
363a314f52aSMasahiro Yamada 			name = env;
364a314f52aSMasahiro Yamada 
365a314f52aSMasahiro Yamada 			in = zconf_fopen(name);
3661da177e4SLinus Torvalds 			if (in) {
367694c49a7SSam Ravnborg 				conf_message("using defaults found in %s",
368a314f52aSMasahiro Yamada 					     name);
369ddc97cacSRoman Zippel 				goto load;
3701da177e4SLinus Torvalds 			}
371b75b0a81SMasahiro Yamada 
372b75b0a81SMasahiro Yamada 			if (is_last)
373b75b0a81SMasahiro Yamada 				break;
374b75b0a81SMasahiro Yamada 
375b75b0a81SMasahiro Yamada 			env = p + 1;
3761da177e4SLinus Torvalds 		}
3771da177e4SLinus Torvalds 	}
3781da177e4SLinus Torvalds 	if (!in)
3791da177e4SLinus Torvalds 		return 1;
3801da177e4SLinus Torvalds 
381ddc97cacSRoman Zippel load:
382c1a0f5e3SRoman Zippel 	conf_filename = name;
383c1a0f5e3SRoman Zippel 	conf_lineno = 0;
384c1a0f5e3SRoman Zippel 	conf_warnings = 0;
385c1a0f5e3SRoman Zippel 
386669bfad9SRoman Zippel 	def_flags = SYMBOL_DEF << def;
38791b69454SMasahiro Yamada 	for_all_symbols(sym) {
388*226ac19cSMasahiro Yamada 		sym->flags &= ~def_flags;
3891da177e4SLinus Torvalds 		switch (sym->type) {
3901da177e4SLinus Torvalds 		case S_INT:
3911da177e4SLinus Torvalds 		case S_HEX:
3921da177e4SLinus Torvalds 		case S_STRING:
393669bfad9SRoman Zippel 			free(sym->def[def].val);
394d8fc3200SArnaud Lacombe 			/* fall through */
3951da177e4SLinus Torvalds 		default:
396669bfad9SRoman Zippel 			sym->def[def].val = NULL;
397669bfad9SRoman Zippel 			sym->def[def].tri = no;
3981da177e4SLinus Torvalds 		}
3991da177e4SLinus Torvalds 	}
4001da177e4SLinus Torvalds 
401*226ac19cSMasahiro Yamada 	if (def == S_DEF_USER) {
402*226ac19cSMasahiro Yamada 		for_all_symbols(sym)
403*226ac19cSMasahiro Yamada 			sym->flags &= ~SYMBOL_VALID;
40495573cacSMasahiro Yamada 		expr_invalidate_all();
405*226ac19cSMasahiro Yamada 	}
40695573cacSMasahiro Yamada 
4079925d6b7SMasahiro Yamada 	while (getline_stripped(&line, &line_asize, in) != -1) {
408f79dc03fSMasahiro Yamada 		struct menu *choice;
409f79dc03fSMasahiro Yamada 
410c1a0f5e3SRoman Zippel 		conf_lineno++;
41148ab6c9cSMasahiro Yamada 
41248ab6c9cSMasahiro Yamada 		if (!line[0]) /* blank line */
41348ab6c9cSMasahiro Yamada 			continue;
41448ab6c9cSMasahiro Yamada 
4158baefd30SArnaud Lacombe 		if (line[0] == '#') {
4164d137ab0SMasahiro Yamada 			if (line[1] != ' ')
4174d137ab0SMasahiro Yamada 				continue;
418d854b4b2SMasahiro Yamada 			p = line + 2;
419d854b4b2SMasahiro Yamada 			if (memcmp(p, CONFIG_, strlen(CONFIG_)))
4201da177e4SLinus Torvalds 				continue;
421d854b4b2SMasahiro Yamada 			sym_name = p + strlen(CONFIG_);
422d854b4b2SMasahiro Yamada 			p = strchr(sym_name, ' ');
4231da177e4SLinus Torvalds 			if (!p)
4241da177e4SLinus Torvalds 				continue;
4251da177e4SLinus Torvalds 			*p++ = 0;
4264aced3ecSMasahiro Yamada 			if (strcmp(p, "is not set"))
4271da177e4SLinus Torvalds 				continue;
42892d4fe0aSMasahiro Yamada 
429d854b4b2SMasahiro Yamada 			val = "n";
4308baefd30SArnaud Lacombe 		} else {
43148ab6c9cSMasahiro Yamada 			if (memcmp(line, CONFIG_, strlen(CONFIG_))) {
4329925d6b7SMasahiro Yamada 				conf_warning("unexpected data: %s", line);
4331da177e4SLinus Torvalds 				continue;
4341da177e4SLinus Torvalds 			}
43575889e9bSMasahiro Yamada 
43648ab6c9cSMasahiro Yamada 			sym_name = line + strlen(CONFIG_);
43748ab6c9cSMasahiro Yamada 			p = strchr(sym_name, '=');
43848ab6c9cSMasahiro Yamada 			if (!p) {
43948ab6c9cSMasahiro Yamada 				conf_warning("unexpected data: %s", line);
44048ab6c9cSMasahiro Yamada 				continue;
44148ab6c9cSMasahiro Yamada 			}
44248ab6c9cSMasahiro Yamada 			*p = 0;
44348ab6c9cSMasahiro Yamada 			val = p + 1;
44448ab6c9cSMasahiro Yamada 		}
44548ab6c9cSMasahiro Yamada 
446d854b4b2SMasahiro Yamada 		sym = sym_find(sym_name);
447d854b4b2SMasahiro Yamada 		if (!sym) {
448d854b4b2SMasahiro Yamada 			if (def == S_DEF_AUTO) {
449d854b4b2SMasahiro Yamada 				/*
450d854b4b2SMasahiro Yamada 				 * Reading from include/config/auto.conf.
451d854b4b2SMasahiro Yamada 				 * If CONFIG_FOO previously existed in auto.conf
452d854b4b2SMasahiro Yamada 				 * but it is missing now, include/config/FOO
453d854b4b2SMasahiro Yamada 				 * must be touched.
454d854b4b2SMasahiro Yamada 				 */
455d854b4b2SMasahiro Yamada 				conf_touch_dep(sym_name);
456d854b4b2SMasahiro Yamada 			} else {
457d854b4b2SMasahiro Yamada 				if (warn_unknown)
458d854b4b2SMasahiro Yamada 					conf_warning("unknown symbol: %s", sym_name);
459d854b4b2SMasahiro Yamada 
460d854b4b2SMasahiro Yamada 				conf_set_changed(true);
461d854b4b2SMasahiro Yamada 			}
462d854b4b2SMasahiro Yamada 			continue;
463d854b4b2SMasahiro Yamada 		}
464d854b4b2SMasahiro Yamada 
465d854b4b2SMasahiro Yamada 		if (sym->flags & def_flags)
466d854b4b2SMasahiro Yamada 			conf_warning("override: reassigning to symbol %s", sym->name);
467d854b4b2SMasahiro Yamada 
468d854b4b2SMasahiro Yamada 		if (conf_set_sym_val(sym, def, def_flags, val))
469d854b4b2SMasahiro Yamada 			continue;
470d854b4b2SMasahiro Yamada 
471*226ac19cSMasahiro Yamada 		if (def != S_DEF_USER)
472*226ac19cSMasahiro Yamada 			continue;
473*226ac19cSMasahiro Yamada 
474f79dc03fSMasahiro Yamada 		/*
475f79dc03fSMasahiro Yamada 		 * If this is a choice member, give it the highest priority.
476f79dc03fSMasahiro Yamada 		 * If conflicting CONFIG options are given from an input file,
477f79dc03fSMasahiro Yamada 		 * the last one wins.
478f79dc03fSMasahiro Yamada 		 */
479f79dc03fSMasahiro Yamada 		choice = sym_get_choice_menu(sym);
480f79dc03fSMasahiro Yamada 		if (choice)
481f79dc03fSMasahiro Yamada 			list_move(&sym->choice_link, &choice->choice_members);
4821da177e4SLinus Torvalds 	}
4831a7a8c6fSCody Schafer 	free(line);
4841da177e4SLinus Torvalds 	fclose(in);
4857cd34300SSergey Senozhatsky 
48690389160SRoman Zippel 	return 0;
48790389160SRoman Zippel }
48890389160SRoman Zippel 
conf_read(const char * name)48990389160SRoman Zippel int conf_read(const char *name)
49090389160SRoman Zippel {
4915d09598dSArnaud Lacombe 	struct symbol *sym;
49290389160SRoman Zippel 
4935ee54659SMasahiro Yamada 	conf_set_changed(false);
494ddc97cacSRoman Zippel 
4956b87b70cSAl Viro 	if (conf_read_simple(name, S_DEF_USER)) {
4966b87b70cSAl Viro 		sym_calc_value(modules_sym);
49790389160SRoman Zippel 		return 1;
4986b87b70cSAl Viro 	}
4996b87b70cSAl Viro 
5006b87b70cSAl Viro 	sym_calc_value(modules_sym);
50190389160SRoman Zippel 
50291b69454SMasahiro Yamada 	for_all_symbols(sym) {
5031da177e4SLinus Torvalds 		sym_calc_value(sym);
504a7c79cf3SMasahiro Yamada 		if (sym_is_choice(sym))
5055d09598dSArnaud Lacombe 			continue;
506c1a0f5e3SRoman Zippel 		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
507c1a0f5e3SRoman Zippel 			/* check that calculated value agrees with saved value */
508c1a0f5e3SRoman Zippel 			switch (sym->type) {
509c1a0f5e3SRoman Zippel 			case S_BOOLEAN:
510c1a0f5e3SRoman Zippel 			case S_TRISTATE:
511e3cd5136SMasahiro Yamada 				if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
5125d09598dSArnaud Lacombe 					continue;
513e3cd5136SMasahiro Yamada 				break;
514c1a0f5e3SRoman Zippel 			default:
5150c1822e6SRoman Zippel 				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
5165d09598dSArnaud Lacombe 					continue;
517c1a0f5e3SRoman Zippel 				break;
518c1a0f5e3SRoman Zippel 			}
519c1a0f5e3SRoman Zippel 		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
520c1a0f5e3SRoman Zippel 			/* no previous value and not saved */
5215d09598dSArnaud Lacombe 			continue;
522cca31837SMasahiro Yamada 		conf_set_changed(true);
523c1a0f5e3SRoman Zippel 		/* maybe print value in verbose mode... */
5241da177e4SLinus Torvalds 	}
5251da177e4SLinus Torvalds 
526cca31837SMasahiro Yamada 	if (conf_warnings)
5275ee54659SMasahiro Yamada 		conf_set_changed(true);
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	return 0;
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds 
532ca51b26bSMasahiro Yamada struct comment_style {
533ca51b26bSMasahiro Yamada 	const char *decoration;
534ca51b26bSMasahiro Yamada 	const char *prefix;
535ca51b26bSMasahiro Yamada 	const char *postfix;
536ca51b26bSMasahiro Yamada };
537ca51b26bSMasahiro Yamada 
538ca51b26bSMasahiro Yamada static const struct comment_style comment_style_pound = {
539ca51b26bSMasahiro Yamada 	.decoration = "#",
540ca51b26bSMasahiro Yamada 	.prefix = "#",
541ca51b26bSMasahiro Yamada 	.postfix = "#",
542ca51b26bSMasahiro Yamada };
543ca51b26bSMasahiro Yamada 
544ca51b26bSMasahiro Yamada static const struct comment_style comment_style_c = {
545ca51b26bSMasahiro Yamada 	.decoration = " *",
546ca51b26bSMasahiro Yamada 	.prefix = "/*",
547ca51b26bSMasahiro Yamada 	.postfix = " */",
548ca51b26bSMasahiro Yamada };
549ca51b26bSMasahiro Yamada 
conf_write_heading(FILE * fp,const struct comment_style * cs)550ca51b26bSMasahiro Yamada static void conf_write_heading(FILE *fp, const struct comment_style *cs)
551ca51b26bSMasahiro Yamada {
5522f7ab126SMiguel Ojeda 	if (!cs)
5532f7ab126SMiguel Ojeda 		return;
5542f7ab126SMiguel Ojeda 
555ca51b26bSMasahiro Yamada 	fprintf(fp, "%s\n", cs->prefix);
556ca51b26bSMasahiro Yamada 
557ca51b26bSMasahiro Yamada 	fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
558ca51b26bSMasahiro Yamada 		cs->decoration);
559ca51b26bSMasahiro Yamada 
560ca51b26bSMasahiro Yamada 	fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
561ca51b26bSMasahiro Yamada 
562ca51b26bSMasahiro Yamada 	fprintf(fp, "%s\n", cs->postfix);
563ca51b26bSMasahiro Yamada }
564ca51b26bSMasahiro Yamada 
56580f7bc77SMasahiro Yamada /* The returned pointer must be freed on the caller side */
escape_string_value(const char * in)56680f7bc77SMasahiro Yamada static char *escape_string_value(const char *in)
56780f7bc77SMasahiro Yamada {
56880f7bc77SMasahiro Yamada 	const char *p;
56980f7bc77SMasahiro Yamada 	char *out;
57080f7bc77SMasahiro Yamada 	size_t len;
57180f7bc77SMasahiro Yamada 
57280f7bc77SMasahiro Yamada 	len = strlen(in) + strlen("\"\"") + 1;
57380f7bc77SMasahiro Yamada 
57480f7bc77SMasahiro Yamada 	p = in;
57580f7bc77SMasahiro Yamada 	while (1) {
57680f7bc77SMasahiro Yamada 		p += strcspn(p, "\"\\");
57780f7bc77SMasahiro Yamada 
57880f7bc77SMasahiro Yamada 		if (p[0] == '\0')
57980f7bc77SMasahiro Yamada 			break;
58080f7bc77SMasahiro Yamada 
58180f7bc77SMasahiro Yamada 		len++;
58280f7bc77SMasahiro Yamada 		p++;
58380f7bc77SMasahiro Yamada 	}
58480f7bc77SMasahiro Yamada 
58580f7bc77SMasahiro Yamada 	out = xmalloc(len);
58680f7bc77SMasahiro Yamada 	out[0] = '\0';
58780f7bc77SMasahiro Yamada 
58880f7bc77SMasahiro Yamada 	strcat(out, "\"");
58980f7bc77SMasahiro Yamada 
59080f7bc77SMasahiro Yamada 	p = in;
59180f7bc77SMasahiro Yamada 	while (1) {
59280f7bc77SMasahiro Yamada 		len = strcspn(p, "\"\\");
59380f7bc77SMasahiro Yamada 		strncat(out, p, len);
59480f7bc77SMasahiro Yamada 		p += len;
59580f7bc77SMasahiro Yamada 
59680f7bc77SMasahiro Yamada 		if (p[0] == '\0')
59780f7bc77SMasahiro Yamada 			break;
59880f7bc77SMasahiro Yamada 
59980f7bc77SMasahiro Yamada 		strcat(out, "\\");
60080f7bc77SMasahiro Yamada 		strncat(out, p++, 1);
60180f7bc77SMasahiro Yamada 	}
60280f7bc77SMasahiro Yamada 
60380f7bc77SMasahiro Yamada 	strcat(out, "\"");
60480f7bc77SMasahiro Yamada 
60580f7bc77SMasahiro Yamada 	return out;
60680f7bc77SMasahiro Yamada }
60780f7bc77SMasahiro Yamada 
6086ce45a91SMasahiro Yamada enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
60949192f26SSam Ravnborg 
__print_symbol(FILE * fp,struct symbol * sym,enum output_n output_n,bool escape_string)6106ce45a91SMasahiro Yamada static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
6116ce45a91SMasahiro Yamada 			   bool escape_string)
612e54e692bSArnaud Lacombe {
613229d0cfaSMasahiro Yamada 	const char *val;
614229d0cfaSMasahiro Yamada 	char *escaped = NULL;
615e54e692bSArnaud Lacombe 
616229d0cfaSMasahiro Yamada 	if (sym->type == S_UNKNOWN)
617229d0cfaSMasahiro Yamada 		return;
618229d0cfaSMasahiro Yamada 
619229d0cfaSMasahiro Yamada 	val = sym_get_string_value(sym);
620229d0cfaSMasahiro Yamada 
6216ce45a91SMasahiro Yamada 	if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
6226ce45a91SMasahiro Yamada 	    output_n != OUTPUT_N && *val == 'n') {
6236ce45a91SMasahiro Yamada 		if (output_n == OUTPUT_N_AS_UNSET)
6246ce45a91SMasahiro Yamada 			fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
6256ce45a91SMasahiro Yamada 		return;
6266ce45a91SMasahiro Yamada 	}
6276ce45a91SMasahiro Yamada 
6286ce45a91SMasahiro Yamada 	if (sym->type == S_STRING && escape_string) {
62980f7bc77SMasahiro Yamada 		escaped = escape_string_value(val);
630229d0cfaSMasahiro Yamada 		val = escaped;
63149192f26SSam Ravnborg 	}
632229d0cfaSMasahiro Yamada 
6336ce45a91SMasahiro Yamada 	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
6346ce45a91SMasahiro Yamada 
6356ce45a91SMasahiro Yamada 	free(escaped);
6366ce45a91SMasahiro Yamada }
6376ce45a91SMasahiro Yamada 
print_symbol_for_dotconfig(FILE * fp,struct symbol * sym)6386ce45a91SMasahiro Yamada static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
6396ce45a91SMasahiro Yamada {
6406ce45a91SMasahiro Yamada 	__print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
6416ce45a91SMasahiro Yamada }
6426ce45a91SMasahiro Yamada 
print_symbol_for_autoconf(FILE * fp,struct symbol * sym)6436ce45a91SMasahiro Yamada static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
6446ce45a91SMasahiro Yamada {
645129ab0d2SMasahiro Yamada 	__print_symbol(fp, sym, OUTPUT_N_NONE, false);
6466ce45a91SMasahiro Yamada }
6476ce45a91SMasahiro Yamada 
print_symbol_for_listconfig(struct symbol * sym)64851d792cbSMasahiro Yamada void print_symbol_for_listconfig(struct symbol *sym)
64951d792cbSMasahiro Yamada {
65051d792cbSMasahiro Yamada 	__print_symbol(stdout, sym, OUTPUT_N, true);
65151d792cbSMasahiro Yamada }
65251d792cbSMasahiro Yamada 
print_symbol_for_c(FILE * fp,struct symbol * sym)6536ce45a91SMasahiro Yamada static void print_symbol_for_c(FILE *fp, struct symbol *sym)
6546ce45a91SMasahiro Yamada {
6556ce45a91SMasahiro Yamada 	const char *val;
6566ce45a91SMasahiro Yamada 	const char *sym_suffix = "";
6576ce45a91SMasahiro Yamada 	const char *val_prefix = "";
6586ce45a91SMasahiro Yamada 	char *escaped = NULL;
6596ce45a91SMasahiro Yamada 
6606ce45a91SMasahiro Yamada 	if (sym->type == S_UNKNOWN)
6616ce45a91SMasahiro Yamada 		return;
6626ce45a91SMasahiro Yamada 
6636ce45a91SMasahiro Yamada 	val = sym_get_string_value(sym);
6646ce45a91SMasahiro Yamada 
6656ce45a91SMasahiro Yamada 	switch (sym->type) {
6666ce45a91SMasahiro Yamada 	case S_BOOLEAN:
6676ce45a91SMasahiro Yamada 	case S_TRISTATE:
6686ce45a91SMasahiro Yamada 		switch (*val) {
6696ce45a91SMasahiro Yamada 		case 'n':
6706ce45a91SMasahiro Yamada 			return;
6716ce45a91SMasahiro Yamada 		case 'm':
6726ce45a91SMasahiro Yamada 			sym_suffix = "_MODULE";
6736ce45a91SMasahiro Yamada 			/* fall through */
6746ce45a91SMasahiro Yamada 		default:
6756ce45a91SMasahiro Yamada 			val = "1";
6766ce45a91SMasahiro Yamada 		}
6776ce45a91SMasahiro Yamada 		break;
6786ce45a91SMasahiro Yamada 	case S_HEX:
6796ce45a91SMasahiro Yamada 		if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
6806ce45a91SMasahiro Yamada 			val_prefix = "0x";
6816ce45a91SMasahiro Yamada 		break;
6826ce45a91SMasahiro Yamada 	case S_STRING:
68380f7bc77SMasahiro Yamada 		escaped = escape_string_value(val);
6846ce45a91SMasahiro Yamada 		val = escaped;
6856ce45a91SMasahiro Yamada 	default:
6866ce45a91SMasahiro Yamada 		break;
6876ce45a91SMasahiro Yamada 	}
6886ce45a91SMasahiro Yamada 
6896ce45a91SMasahiro Yamada 	fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
6906ce45a91SMasahiro Yamada 		val_prefix, val);
691229d0cfaSMasahiro Yamada 
692229d0cfaSMasahiro Yamada 	free(escaped);
69349192f26SSam Ravnborg }
69449192f26SSam Ravnborg 
print_symbol_for_rustccfg(FILE * fp,struct symbol * sym)6952f7ab126SMiguel Ojeda static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
6962f7ab126SMiguel Ojeda {
6972f7ab126SMiguel Ojeda 	const char *val;
6982f7ab126SMiguel Ojeda 	const char *val_prefix = "";
6992f7ab126SMiguel Ojeda 	char *val_prefixed = NULL;
7002f7ab126SMiguel Ojeda 	size_t val_prefixed_len;
7012f7ab126SMiguel Ojeda 	char *escaped = NULL;
7022f7ab126SMiguel Ojeda 
7032f7ab126SMiguel Ojeda 	if (sym->type == S_UNKNOWN)
7042f7ab126SMiguel Ojeda 		return;
7052f7ab126SMiguel Ojeda 
7062f7ab126SMiguel Ojeda 	val = sym_get_string_value(sym);
7072f7ab126SMiguel Ojeda 
7082f7ab126SMiguel Ojeda 	switch (sym->type) {
7092f7ab126SMiguel Ojeda 	case S_BOOLEAN:
7102f7ab126SMiguel Ojeda 	case S_TRISTATE:
7112f7ab126SMiguel Ojeda 		/*
7122f7ab126SMiguel Ojeda 		 * We do not care about disabled ones, i.e. no need for
7132f7ab126SMiguel Ojeda 		 * what otherwise are "comments" in other printers.
7142f7ab126SMiguel Ojeda 		 */
7152f7ab126SMiguel Ojeda 		if (*val == 'n')
7162f7ab126SMiguel Ojeda 			return;
7172f7ab126SMiguel Ojeda 
7182f7ab126SMiguel Ojeda 		/*
7192f7ab126SMiguel Ojeda 		 * To have similar functionality to the C macro `IS_ENABLED()`
7202f7ab126SMiguel Ojeda 		 * we provide an empty `--cfg CONFIG_X` here in both `y`
7212f7ab126SMiguel Ojeda 		 * and `m` cases.
7222f7ab126SMiguel Ojeda 		 *
7232f7ab126SMiguel Ojeda 		 * Then, the common `fprintf()` below will also give us
7242f7ab126SMiguel Ojeda 		 * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
7252f7ab126SMiguel Ojeda 		 * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
7262f7ab126SMiguel Ojeda 		 */
7272f7ab126SMiguel Ojeda 		fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
7282f7ab126SMiguel Ojeda 		break;
7292f7ab126SMiguel Ojeda 	case S_HEX:
7302f7ab126SMiguel Ojeda 		if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
7312f7ab126SMiguel Ojeda 			val_prefix = "0x";
7322f7ab126SMiguel Ojeda 		break;
7332f7ab126SMiguel Ojeda 	default:
7342f7ab126SMiguel Ojeda 		break;
7352f7ab126SMiguel Ojeda 	}
7362f7ab126SMiguel Ojeda 
7372f7ab126SMiguel Ojeda 	if (strlen(val_prefix) > 0) {
7382f7ab126SMiguel Ojeda 		val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
7392f7ab126SMiguel Ojeda 		val_prefixed = xmalloc(val_prefixed_len);
7402f7ab126SMiguel Ojeda 		snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
7412f7ab126SMiguel Ojeda 		val = val_prefixed;
7422f7ab126SMiguel Ojeda 	}
7432f7ab126SMiguel Ojeda 
7442f7ab126SMiguel Ojeda 	/* All values get escaped: the `--cfg` option only takes strings */
7452f7ab126SMiguel Ojeda 	escaped = escape_string_value(val);
7462f7ab126SMiguel Ojeda 	val = escaped;
7472f7ab126SMiguel Ojeda 
7482f7ab126SMiguel Ojeda 	fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
7492f7ab126SMiguel Ojeda 
7502f7ab126SMiguel Ojeda 	free(escaped);
7512f7ab126SMiguel Ojeda 	free(val_prefixed);
7522f7ab126SMiguel Ojeda }
7532f7ab126SMiguel Ojeda 
7547cf3d73bSSam Ravnborg /*
7557cf3d73bSSam Ravnborg  * Write out a minimal config.
7567cf3d73bSSam Ravnborg  * All values that has default values are skipped as this is redundant.
7577cf3d73bSSam Ravnborg  */
conf_write_defconfig(const char * filename)7587cf3d73bSSam Ravnborg int conf_write_defconfig(const char *filename)
7597cf3d73bSSam Ravnborg {
7607cf3d73bSSam Ravnborg 	struct symbol *sym;
7617cf3d73bSSam Ravnborg 	struct menu *menu;
7627cf3d73bSSam Ravnborg 	FILE *out;
7637cf3d73bSSam Ravnborg 
7647cf3d73bSSam Ravnborg 	out = fopen(filename, "w");
7657cf3d73bSSam Ravnborg 	if (!out)
7667cf3d73bSSam Ravnborg 		return 1;
7677cf3d73bSSam Ravnborg 
7687cf3d73bSSam Ravnborg 	sym_clear_all_valid();
7697cf3d73bSSam Ravnborg 
77003c4ecaaSMasahiro Yamada 	menu_for_each_entry(menu) {
771fb8dd482SMasahiro Yamada 		struct menu *choice;
772fb8dd482SMasahiro Yamada 
7737cf3d73bSSam Ravnborg 		sym = menu->sym;
774995150e4SMasahiro Yamada 
775995150e4SMasahiro Yamada 		if (!sym || sym_is_choice(sym))
776995150e4SMasahiro Yamada 			continue;
777995150e4SMasahiro Yamada 
7787cf3d73bSSam Ravnborg 		sym_calc_value(sym);
7797cf3d73bSSam Ravnborg 		if (!(sym->flags & SYMBOL_WRITE))
78003c4ecaaSMasahiro Yamada 			continue;
7817cf3d73bSSam Ravnborg 		sym->flags &= ~SYMBOL_WRITE;
782995150e4SMasahiro Yamada 		/* Skip unchangeable symbols */
783baa23ec8SMarco Ammon 		if (!sym_is_changeable(sym))
78403c4ecaaSMasahiro Yamada 			continue;
785995150e4SMasahiro Yamada 		/* Skip symbols that are equal to the default */
786995150e4SMasahiro Yamada 		if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
78703c4ecaaSMasahiro Yamada 			continue;
7887cf3d73bSSam Ravnborg 
789995150e4SMasahiro Yamada 		/* Skip choice values that are equal to the default */
790fb8dd482SMasahiro Yamada 		choice = sym_get_choice_menu(sym);
791fb8dd482SMasahiro Yamada 		if (choice) {
7927cf3d73bSSam Ravnborg 			struct symbol *ds;
7937cf3d73bSSam Ravnborg 
794e8fcd915SMasahiro Yamada 			ds = sym_choice_default(choice);
795995150e4SMasahiro Yamada 			if (sym == ds && sym_get_tristate_value(sym) == yes)
79603c4ecaaSMasahiro Yamada 				continue;
7977cf3d73bSSam Ravnborg 		}
7986ce45a91SMasahiro Yamada 		print_symbol_for_dotconfig(out, sym);
7997cf3d73bSSam Ravnborg 	}
8007cf3d73bSSam Ravnborg 	fclose(out);
8017cf3d73bSSam Ravnborg 	return 0;
8027cf3d73bSSam Ravnborg }
8037cf3d73bSSam Ravnborg 
conf_write(const char * name)8041da177e4SLinus Torvalds int conf_write(const char *name)
8051da177e4SLinus Torvalds {
806c955ccafSRoman Zippel 	FILE *out;
8071da177e4SLinus Torvalds 	struct symbol *sym;
8081da177e4SLinus Torvalds 	struct menu *menu;
8091da177e4SLinus Torvalds 	const char *str;
810ceb7f329SMasahiro Yamada 	char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
8111da177e4SLinus Torvalds 	char *env;
812aff11cd9SAlexander Popov 	bool need_newline = false;
8131da177e4SLinus Torvalds 
814ceb7f329SMasahiro Yamada 	if (!name)
815ceb7f329SMasahiro Yamada 		name = conf_get_configname();
816ceb7f329SMasahiro Yamada 
817ceb7f329SMasahiro Yamada 	if (!*name) {
818ceb7f329SMasahiro Yamada 		fprintf(stderr, "config name is empty\n");
819ceb7f329SMasahiro Yamada 		return -1;
820ceb7f329SMasahiro Yamada 	}
8211da177e4SLinus Torvalds 
8220608182aSMasahiro Yamada 	if (is_dir(name)) {
823ceb7f329SMasahiro Yamada 		fprintf(stderr, "%s: Is a directory\n", name);
824ceb7f329SMasahiro Yamada 		return -1;
825ceb7f329SMasahiro Yamada 	}
8261da177e4SLinus Torvalds 
827580c5b3eSMasahiro Yamada 	if (make_parent_dir(name))
828580c5b3eSMasahiro Yamada 		return -1;
829580c5b3eSMasahiro Yamada 
83014cdd3c4SRoman Zippel 	env = getenv("KCONFIG_OVERWRITECONFIG");
831ceb7f329SMasahiro Yamada 	if (env && *env) {
83214cdd3c4SRoman Zippel 		*tmpname = 0;
833ceb7f329SMasahiro Yamada 		out = fopen(name, "w");
834ceb7f329SMasahiro Yamada 	} else {
835ceb7f329SMasahiro Yamada 		snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
836ceb7f329SMasahiro Yamada 			 name, (int)getpid());
837ceb7f329SMasahiro Yamada 		out = fopen(tmpname, "w");
83814cdd3c4SRoman Zippel 	}
8391da177e4SLinus Torvalds 	if (!out)
8401da177e4SLinus Torvalds 		return 1;
84114cdd3c4SRoman Zippel 
842ca51b26bSMasahiro Yamada 	conf_write_heading(out, &comment_style_pound);
8431da177e4SLinus Torvalds 
844b3214293SKarsten Wiese 	if (!conf_get_changed())
8451da177e4SLinus Torvalds 		sym_clear_all_valid();
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 	menu = rootmenu.list;
8481da177e4SLinus Torvalds 	while (menu) {
8491da177e4SLinus Torvalds 		sym = menu->sym;
8501da177e4SLinus Torvalds 		if (!sym) {
8511da177e4SLinus Torvalds 			if (!menu_is_visible(menu))
8521da177e4SLinus Torvalds 				goto next;
8531da177e4SLinus Torvalds 			str = menu_get_prompt(menu);
8541da177e4SLinus Torvalds 			fprintf(out, "\n"
8551da177e4SLinus Torvalds 				     "#\n"
8561da177e4SLinus Torvalds 				     "# %s\n"
8571da177e4SLinus Torvalds 				     "#\n", str);
858aff11cd9SAlexander Popov 			need_newline = false;
8591da251c6SMasahiro Yamada 		} else if (!sym_is_choice(sym) &&
8608e2442a5SMasahiro Yamada 			   !(sym->flags & SYMBOL_WRITTEN)) {
8611da177e4SLinus Torvalds 			sym_calc_value(sym);
8621da177e4SLinus Torvalds 			if (!(sym->flags & SYMBOL_WRITE))
8631da177e4SLinus Torvalds 				goto next;
864aff11cd9SAlexander Popov 			if (need_newline) {
865aff11cd9SAlexander Popov 				fprintf(out, "\n");
866aff11cd9SAlexander Popov 				need_newline = false;
867aff11cd9SAlexander Popov 			}
8688e2442a5SMasahiro Yamada 			sym->flags |= SYMBOL_WRITTEN;
8696ce45a91SMasahiro Yamada 			print_symbol_for_dotconfig(out, sym);
8701da177e4SLinus Torvalds 		}
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds next:
8731da177e4SLinus Torvalds 		if (menu->list) {
8741da177e4SLinus Torvalds 			menu = menu->list;
8751da177e4SLinus Torvalds 			continue;
8761da177e4SLinus Torvalds 		}
877a7d4f58eSMasahiro Yamada 
878a7d4f58eSMasahiro Yamada end_check:
879a7d4f58eSMasahiro Yamada 		if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
880a7d4f58eSMasahiro Yamada 		    menu->prompt->type == P_MENU) {
881a7d4f58eSMasahiro Yamada 			fprintf(out, "# end of %s\n", menu_get_prompt(menu));
882aff11cd9SAlexander Popov 			need_newline = true;
883aff11cd9SAlexander Popov 		}
884a7d4f58eSMasahiro Yamada 
8851da177e4SLinus Torvalds 		if (menu->next) {
8861da177e4SLinus Torvalds 			menu = menu->next;
887a7d4f58eSMasahiro Yamada 		} else {
888a7d4f58eSMasahiro Yamada 			menu = menu->parent;
889a7d4f58eSMasahiro Yamada 			if (menu)
890a7d4f58eSMasahiro Yamada 				goto end_check;
8911da177e4SLinus Torvalds 		}
8921da177e4SLinus Torvalds 	}
8931da177e4SLinus Torvalds 	fclose(out);
89414cdd3c4SRoman Zippel 
89591b69454SMasahiro Yamada 	for_all_symbols(sym)
8960c5b6c28SM. Vefa Bicakci 		sym->flags &= ~SYMBOL_WRITTEN;
8970c5b6c28SM. Vefa Bicakci 
89814cdd3c4SRoman Zippel 	if (*tmpname) {
89967424f61SMasahiro Yamada 		if (is_same(name, tmpname)) {
90067424f61SMasahiro Yamada 			conf_message("No change to %s", name);
90167424f61SMasahiro Yamada 			unlink(tmpname);
9025ee54659SMasahiro Yamada 			conf_set_changed(false);
90367424f61SMasahiro Yamada 			return 0;
90467424f61SMasahiro Yamada 		}
90567424f61SMasahiro Yamada 
906ceb7f329SMasahiro Yamada 		snprintf(oldname, sizeof(oldname), "%s.old", name);
907ceb7f329SMasahiro Yamada 		rename(name, oldname);
908ceb7f329SMasahiro Yamada 		if (rename(tmpname, name))
9091da177e4SLinus Torvalds 			return 1;
91014cdd3c4SRoman Zippel 	}
9111da177e4SLinus Torvalds 
912ceb7f329SMasahiro Yamada 	conf_message("configuration written to %s", name);
913ddc97cacSRoman Zippel 
9145ee54659SMasahiro Yamada 	conf_set_changed(false);
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 	return 0;
9171da177e4SLinus Torvalds }
918c955ccafSRoman Zippel 
919a2ff4040SMasahiro Yamada /* write a dependency file as used by kbuild to track dependencies */
conf_write_autoconf_cmd(const char * autoconf_name)92000d674cbSMasahiro Yamada static int conf_write_autoconf_cmd(const char *autoconf_name)
921a2ff4040SMasahiro Yamada {
92200d674cbSMasahiro Yamada 	char name[PATH_MAX], tmp[PATH_MAX];
923a2ff4040SMasahiro Yamada 	FILE *out;
92400d674cbSMasahiro Yamada 	int ret;
925a2ff4040SMasahiro Yamada 
92600d674cbSMasahiro Yamada 	ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
92700d674cbSMasahiro Yamada 	if (ret >= sizeof(name)) /* check truncation */
92800d674cbSMasahiro Yamada 		return -1;
92979123b13SMasahiro Yamada 
93079123b13SMasahiro Yamada 	if (make_parent_dir(name))
93100d674cbSMasahiro Yamada 		return -1;
93200d674cbSMasahiro Yamada 
93300d674cbSMasahiro Yamada 	ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
93400d674cbSMasahiro Yamada 	if (ret >= sizeof(tmp)) /* check truncation */
93500d674cbSMasahiro Yamada 		return -1;
93600d674cbSMasahiro Yamada 
93700d674cbSMasahiro Yamada 	out = fopen(tmp, "w");
93800d674cbSMasahiro Yamada 	if (!out) {
93900d674cbSMasahiro Yamada 		perror("fopen");
94000d674cbSMasahiro Yamada 		return -1;
94100d674cbSMasahiro Yamada 	}
94200d674cbSMasahiro Yamada 
94356e634b0SMasahiro Yamada 	fprintf(out, "autoconfig := %s\n", autoconf_name);
94456e634b0SMasahiro Yamada 
945526396b7SMasahiro Yamada 	fputs(str_get(&autoconf_cmd), out);
94600d674cbSMasahiro Yamada 
947868653f4SMasahiro Yamada 	fflush(out);
948d23a0c37SMasahiro Yamada 	ret = ferror(out); /* error check for all fprintf() calls */
94900d674cbSMasahiro Yamada 	fclose(out);
950d23a0c37SMasahiro Yamada 	if (ret)
951d23a0c37SMasahiro Yamada 		return -1;
95200d674cbSMasahiro Yamada 
95300d674cbSMasahiro Yamada 	if (rename(tmp, name)) {
95400d674cbSMasahiro Yamada 		perror("rename");
95500d674cbSMasahiro Yamada 		return -1;
95600d674cbSMasahiro Yamada 	}
95700d674cbSMasahiro Yamada 
958a2ff4040SMasahiro Yamada 	return 0;
959a2ff4040SMasahiro Yamada }
960a2ff4040SMasahiro Yamada 
conf_touch_deps(void)9610849d212SMasahiro Yamada static int conf_touch_deps(void)
9622e3646e5SRoman Zippel {
9631b9e740aSJing Leng 	const char *name, *tmp;
9642e3646e5SRoman Zippel 	struct symbol *sym;
96591b69454SMasahiro Yamada 	int res;
9661508fec8SMasahiro Yamada 
96712122f62SMarkus Heidelberg 	name = conf_get_autoconfig_name();
9681b9e740aSJing Leng 	tmp = strrchr(name, '/');
9691b9e740aSJing Leng 	depfile_prefix_len = tmp ? tmp - name + 1 : 0;
9701b9e740aSJing Leng 	if (depfile_prefix_len + 1 > sizeof(depfile_path))
9711b9e740aSJing Leng 		return -1;
9721b9e740aSJing Leng 
9731b9e740aSJing Leng 	strncpy(depfile_path, name, depfile_prefix_len);
9741b9e740aSJing Leng 	depfile_path[depfile_prefix_len] = 0;
9751b9e740aSJing Leng 
9762e3646e5SRoman Zippel 	conf_read_simple(name, S_DEF_AUTO);
9772e3646e5SRoman Zippel 
97891b69454SMasahiro Yamada 	for_all_symbols(sym) {
979a7c79cf3SMasahiro Yamada 		if (sym_is_choice(sym))
9802e3646e5SRoman Zippel 			continue;
9812e3646e5SRoman Zippel 		if (sym->flags & SYMBOL_WRITE) {
9822e3646e5SRoman Zippel 			if (sym->flags & SYMBOL_DEF_AUTO) {
9832e3646e5SRoman Zippel 				/*
9842e3646e5SRoman Zippel 				 * symbol has old and new value,
9852e3646e5SRoman Zippel 				 * so compare them...
9862e3646e5SRoman Zippel 				 */
9872e3646e5SRoman Zippel 				switch (sym->type) {
9882e3646e5SRoman Zippel 				case S_BOOLEAN:
9892e3646e5SRoman Zippel 				case S_TRISTATE:
9902e3646e5SRoman Zippel 					if (sym_get_tristate_value(sym) ==
9912e3646e5SRoman Zippel 					    sym->def[S_DEF_AUTO].tri)
9922e3646e5SRoman Zippel 						continue;
9932e3646e5SRoman Zippel 					break;
9942e3646e5SRoman Zippel 				case S_STRING:
9952e3646e5SRoman Zippel 				case S_HEX:
9962e3646e5SRoman Zippel 				case S_INT:
9972e3646e5SRoman Zippel 					if (!strcmp(sym_get_string_value(sym),
9982e3646e5SRoman Zippel 						    sym->def[S_DEF_AUTO].val))
9992e3646e5SRoman Zippel 						continue;
10002e3646e5SRoman Zippel 					break;
10012e3646e5SRoman Zippel 				default:
10022e3646e5SRoman Zippel 					break;
10032e3646e5SRoman Zippel 				}
10042e3646e5SRoman Zippel 			} else {
10052e3646e5SRoman Zippel 				/*
10062e3646e5SRoman Zippel 				 * If there is no old value, only 'no' (unset)
10072e3646e5SRoman Zippel 				 * is allowed as new value.
10082e3646e5SRoman Zippel 				 */
10092e3646e5SRoman Zippel 				switch (sym->type) {
10102e3646e5SRoman Zippel 				case S_BOOLEAN:
10112e3646e5SRoman Zippel 				case S_TRISTATE:
10122e3646e5SRoman Zippel 					if (sym_get_tristate_value(sym) == no)
10132e3646e5SRoman Zippel 						continue;
10142e3646e5SRoman Zippel 					break;
10152e3646e5SRoman Zippel 				default:
10162e3646e5SRoman Zippel 					break;
10172e3646e5SRoman Zippel 				}
10182e3646e5SRoman Zippel 			}
10192e3646e5SRoman Zippel 		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
10202e3646e5SRoman Zippel 			/* There is neither an old nor a new value. */
10212e3646e5SRoman Zippel 			continue;
10222e3646e5SRoman Zippel 		/* else
10232e3646e5SRoman Zippel 		 *	There is an old value, but no new value ('no' (unset)
10242e3646e5SRoman Zippel 		 *	isn't saved in auto.conf, so the old value is always
10252e3646e5SRoman Zippel 		 *	different from 'no').
10262e3646e5SRoman Zippel 		 */
10272e3646e5SRoman Zippel 
10281508fec8SMasahiro Yamada 		res = conf_touch_dep(sym->name);
10291508fec8SMasahiro Yamada 		if (res)
10302e3646e5SRoman Zippel 			return res;
10312e3646e5SRoman Zippel 	}
10322e3646e5SRoman Zippel 
10331508fec8SMasahiro Yamada 	return 0;
10341508fec8SMasahiro Yamada }
10351508fec8SMasahiro Yamada 
__conf_write_autoconf(const char * filename,void (* print_symbol)(FILE *,struct symbol *),const struct comment_style * comment_style)103657ddd07cSMasahiro Yamada static int __conf_write_autoconf(const char *filename,
103757ddd07cSMasahiro Yamada 				 void (*print_symbol)(FILE *, struct symbol *),
103857ddd07cSMasahiro Yamada 				 const struct comment_style *comment_style)
103957ddd07cSMasahiro Yamada {
104057ddd07cSMasahiro Yamada 	char tmp[PATH_MAX];
104157ddd07cSMasahiro Yamada 	FILE *file;
104257ddd07cSMasahiro Yamada 	struct symbol *sym;
104391b69454SMasahiro Yamada 	int ret;
104457ddd07cSMasahiro Yamada 
104557ddd07cSMasahiro Yamada 	if (make_parent_dir(filename))
104657ddd07cSMasahiro Yamada 		return -1;
104757ddd07cSMasahiro Yamada 
104857ddd07cSMasahiro Yamada 	ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
104957ddd07cSMasahiro Yamada 	if (ret >= sizeof(tmp)) /* check truncation */
105057ddd07cSMasahiro Yamada 		return -1;
105157ddd07cSMasahiro Yamada 
105257ddd07cSMasahiro Yamada 	file = fopen(tmp, "w");
105357ddd07cSMasahiro Yamada 	if (!file) {
105457ddd07cSMasahiro Yamada 		perror("fopen");
105557ddd07cSMasahiro Yamada 		return -1;
105657ddd07cSMasahiro Yamada 	}
105757ddd07cSMasahiro Yamada 
105857ddd07cSMasahiro Yamada 	conf_write_heading(file, comment_style);
105957ddd07cSMasahiro Yamada 
106091b69454SMasahiro Yamada 	for_all_symbols(sym)
106157ddd07cSMasahiro Yamada 		if ((sym->flags & SYMBOL_WRITE) && sym->name)
106257ddd07cSMasahiro Yamada 			print_symbol(file, sym);
106357ddd07cSMasahiro Yamada 
1064868653f4SMasahiro Yamada 	fflush(file);
106557ddd07cSMasahiro Yamada 	/* check possible errors in conf_write_heading() and print_symbol() */
1066d23a0c37SMasahiro Yamada 	ret = ferror(file);
106757ddd07cSMasahiro Yamada 	fclose(file);
1068d23a0c37SMasahiro Yamada 	if (ret)
1069d23a0c37SMasahiro Yamada 		return -1;
107057ddd07cSMasahiro Yamada 
107157ddd07cSMasahiro Yamada 	if (rename(tmp, filename)) {
107257ddd07cSMasahiro Yamada 		perror("rename");
107357ddd07cSMasahiro Yamada 		return -1;
107457ddd07cSMasahiro Yamada 	}
107557ddd07cSMasahiro Yamada 
107657ddd07cSMasahiro Yamada 	return 0;
107757ddd07cSMasahiro Yamada }
107857ddd07cSMasahiro Yamada 
conf_write_autoconf(int overwrite)107900c864f8SMasahiro Yamada int conf_write_autoconf(int overwrite)
1080c955ccafSRoman Zippel {
1081c955ccafSRoman Zippel 	struct symbol *sym;
108200c864f8SMasahiro Yamada 	const char *autoconf_name = conf_get_autoconfig_name();
108391b69454SMasahiro Yamada 	int ret;
1084c955ccafSRoman Zippel 
108500c864f8SMasahiro Yamada 	if (!overwrite && is_present(autoconf_name))
108600c864f8SMasahiro Yamada 		return 0;
108700c864f8SMasahiro Yamada 
108800d674cbSMasahiro Yamada 	ret = conf_write_autoconf_cmd(autoconf_name);
108900d674cbSMasahiro Yamada 	if (ret)
109000d674cbSMasahiro Yamada 		return -1;
1091c955ccafSRoman Zippel 
109291b69454SMasahiro Yamada 	for_all_symbols(sym)
1093953742c8SArnaud Lacombe 		sym_calc_value(sym);
1094953742c8SArnaud Lacombe 
1095*226ac19cSMasahiro Yamada 	if (conf_touch_deps())
1096*226ac19cSMasahiro Yamada 		return 1;
1097*226ac19cSMasahiro Yamada 
109857ddd07cSMasahiro Yamada 	ret = __conf_write_autoconf(conf_get_autoheader_name(),
109957ddd07cSMasahiro Yamada 				    print_symbol_for_c,
110057ddd07cSMasahiro Yamada 				    &comment_style_c);
110157ddd07cSMasahiro Yamada 	if (ret)
110257ddd07cSMasahiro Yamada 		return ret;
1103c955ccafSRoman Zippel 
11042f7ab126SMiguel Ojeda 	ret = __conf_write_autoconf(conf_get_rustccfg_name(),
11052f7ab126SMiguel Ojeda 				    print_symbol_for_rustccfg,
11062f7ab126SMiguel Ojeda 				    NULL);
11072f7ab126SMiguel Ojeda 	if (ret)
11082f7ab126SMiguel Ojeda 		return ret;
11092f7ab126SMiguel Ojeda 
1110c955ccafSRoman Zippel 	/*
111157ddd07cSMasahiro Yamada 	 * Create include/config/auto.conf. This must be the last step because
111257ddd07cSMasahiro Yamada 	 * Kbuild has a dependency on auto.conf and this marks the successful
111357ddd07cSMasahiro Yamada 	 * completion of the previous steps.
1114c955ccafSRoman Zippel 	 */
111557ddd07cSMasahiro Yamada 	ret = __conf_write_autoconf(conf_get_autoconfig_name(),
111657ddd07cSMasahiro Yamada 				    print_symbol_for_autoconf,
111757ddd07cSMasahiro Yamada 				    &comment_style_pound);
111857ddd07cSMasahiro Yamada 	if (ret)
111957ddd07cSMasahiro Yamada 		return ret;
1120c955ccafSRoman Zippel 
1121c955ccafSRoman Zippel 	return 0;
1122c955ccafSRoman Zippel }
1123b3214293SKarsten Wiese 
11245ee54659SMasahiro Yamada static bool conf_changed;
112503638aaaSMasahiro Yamada static void (*conf_changed_callback)(bool);
1126bfc10001SKarsten Wiese 
conf_set_changed(bool val)11275ee54659SMasahiro Yamada void conf_set_changed(bool val)
1128bfc10001SKarsten Wiese {
112903638aaaSMasahiro Yamada 	if (conf_changed_callback && conf_changed != val)
113003638aaaSMasahiro Yamada 		conf_changed_callback(val);
1131bfc10001SKarsten Wiese 
11325ee54659SMasahiro Yamada 	conf_changed = val;
1133bfc10001SKarsten Wiese }
1134bfc10001SKarsten Wiese 
conf_get_changed(void)1135b3214293SKarsten Wiese bool conf_get_changed(void)
1136b3214293SKarsten Wiese {
11375ee54659SMasahiro Yamada 	return conf_changed;
1138b3214293SKarsten Wiese }
11393b354c55SKarsten Wiese 
conf_set_changed_callback(void (* fn)(bool))114003638aaaSMasahiro Yamada void conf_set_changed_callback(void (*fn)(bool))
11413b354c55SKarsten Wiese {
11423b354c55SKarsten Wiese 	conf_changed_callback = fn;
11433b354c55SKarsten Wiese }
1144