18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <sys/mman.h>
78c2ecf20Sopenharmony_ci#include <sys/stat.h>
88c2ecf20Sopenharmony_ci#include <ctype.h>
98c2ecf20Sopenharmony_ci#include <errno.h>
108c2ecf20Sopenharmony_ci#include <fcntl.h>
118c2ecf20Sopenharmony_ci#include <limits.h>
128c2ecf20Sopenharmony_ci#include <stdarg.h>
138c2ecf20Sopenharmony_ci#include <stdio.h>
148c2ecf20Sopenharmony_ci#include <stdlib.h>
158c2ecf20Sopenharmony_ci#include <string.h>
168c2ecf20Sopenharmony_ci#include <time.h>
178c2ecf20Sopenharmony_ci#include <unistd.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "lkc.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* return true if 'path' exists, false otherwise */
228c2ecf20Sopenharmony_cistatic bool is_present(const char *path)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct stat st;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	return !stat(path, &st);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* return true if 'path' exists and it is a directory, false otherwise */
308c2ecf20Sopenharmony_cistatic bool is_dir(const char *path)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct stat st;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (stat(path, &st))
358c2ecf20Sopenharmony_ci		return 0;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return S_ISDIR(st.st_mode);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* return true if the given two files are the same, false otherwise */
418c2ecf20Sopenharmony_cistatic bool is_same(const char *file1, const char *file2)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	int fd1, fd2;
448c2ecf20Sopenharmony_ci	struct stat st1, st2;
458c2ecf20Sopenharmony_ci	void *map1, *map2;
468c2ecf20Sopenharmony_ci	bool ret = false;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	fd1 = open(file1, O_RDONLY);
498c2ecf20Sopenharmony_ci	if (fd1 < 0)
508c2ecf20Sopenharmony_ci		return ret;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	fd2 = open(file2, O_RDONLY);
538c2ecf20Sopenharmony_ci	if (fd2 < 0)
548c2ecf20Sopenharmony_ci		goto close1;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	ret = fstat(fd1, &st1);
578c2ecf20Sopenharmony_ci	if (ret)
588c2ecf20Sopenharmony_ci		goto close2;
598c2ecf20Sopenharmony_ci	ret = fstat(fd2, &st2);
608c2ecf20Sopenharmony_ci	if (ret)
618c2ecf20Sopenharmony_ci		goto close2;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (st1.st_size != st2.st_size)
648c2ecf20Sopenharmony_ci		goto close2;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
678c2ecf20Sopenharmony_ci	if (map1 == MAP_FAILED)
688c2ecf20Sopenharmony_ci		goto close2;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
718c2ecf20Sopenharmony_ci	if (map2 == MAP_FAILED)
728c2ecf20Sopenharmony_ci		goto close2;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (bcmp(map1, map2, st1.st_size))
758c2ecf20Sopenharmony_ci		goto close2;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	ret = true;
788c2ecf20Sopenharmony_ciclose2:
798c2ecf20Sopenharmony_ci	close(fd2);
808c2ecf20Sopenharmony_ciclose1:
818c2ecf20Sopenharmony_ci	close(fd1);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return ret;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/*
878c2ecf20Sopenharmony_ci * Create the parent directory of the given path.
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * For example, if 'include/config/auto.conf' is given, create 'include/config'.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_cistatic int make_parent_dir(const char *path)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	char tmp[PATH_MAX + 1];
948c2ecf20Sopenharmony_ci	char *p;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	strncpy(tmp, path, sizeof(tmp));
978c2ecf20Sopenharmony_ci	tmp[sizeof(tmp) - 1] = 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* Remove the base name. Just return if nothing is left */
1008c2ecf20Sopenharmony_ci	p = strrchr(tmp, '/');
1018c2ecf20Sopenharmony_ci	if (!p)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci	*(p + 1) = 0;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* Just in case it is an absolute path */
1068c2ecf20Sopenharmony_ci	p = tmp;
1078c2ecf20Sopenharmony_ci	while (*p == '/')
1088c2ecf20Sopenharmony_ci		p++;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	while ((p = strchr(p, '/'))) {
1118c2ecf20Sopenharmony_ci		*p = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		/* skip if the directory exists */
1148c2ecf20Sopenharmony_ci		if (!is_dir(tmp) && mkdir(tmp, 0755))
1158c2ecf20Sopenharmony_ci			return -1;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		*p = '/';
1188c2ecf20Sopenharmony_ci		while (*p == '/')
1198c2ecf20Sopenharmony_ci			p++;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return 0;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic char depfile_path[PATH_MAX];
1268c2ecf20Sopenharmony_cistatic size_t depfile_prefix_len;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* touch depfile for symbol 'name' */
1298c2ecf20Sopenharmony_cistatic int conf_touch_dep(const char *name)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int fd, ret;
1328c2ecf20Sopenharmony_ci	const char *s;
1338c2ecf20Sopenharmony_ci	char *d, c;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
1368c2ecf20Sopenharmony_ci	if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
1378c2ecf20Sopenharmony_ci		return -1;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	d = depfile_path + depfile_prefix_len;
1408c2ecf20Sopenharmony_ci	s = name;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	while ((c = *s++))
1438c2ecf20Sopenharmony_ci		*d++ = (c == '_') ? '/' : tolower(c);
1448c2ecf20Sopenharmony_ci	strcpy(d, ".h");
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Assume directory path already exists. */
1478c2ecf20Sopenharmony_ci	fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1488c2ecf20Sopenharmony_ci	if (fd == -1) {
1498c2ecf20Sopenharmony_ci		if (errno != ENOENT)
1508c2ecf20Sopenharmony_ci			return -1;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		ret = make_parent_dir(depfile_path);
1538c2ecf20Sopenharmony_ci		if (ret)
1548c2ecf20Sopenharmony_ci			return ret;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		/* Try it again. */
1578c2ecf20Sopenharmony_ci		fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1588c2ecf20Sopenharmony_ci		if (fd == -1)
1598c2ecf20Sopenharmony_ci			return -1;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci	close(fd);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistruct conf_printer {
1678c2ecf20Sopenharmony_ci	void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
1688c2ecf20Sopenharmony_ci	void (*print_comment)(FILE *, const char *, void *);
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void conf_warning(const char *fmt, ...)
1728c2ecf20Sopenharmony_ci	__attribute__ ((format (printf, 1, 2)));
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic void conf_message(const char *fmt, ...)
1758c2ecf20Sopenharmony_ci	__attribute__ ((format (printf, 1, 2)));
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic const char *conf_filename;
1788c2ecf20Sopenharmony_cistatic int conf_lineno, conf_warnings;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic void conf_warning(const char *fmt, ...)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	va_list ap;
1838c2ecf20Sopenharmony_ci	va_start(ap, fmt);
1848c2ecf20Sopenharmony_ci	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
1858c2ecf20Sopenharmony_ci	vfprintf(stderr, fmt, ap);
1868c2ecf20Sopenharmony_ci	fprintf(stderr, "\n");
1878c2ecf20Sopenharmony_ci	va_end(ap);
1888c2ecf20Sopenharmony_ci	conf_warnings++;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void conf_default_message_callback(const char *s)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	printf("#\n# ");
1948c2ecf20Sopenharmony_ci	printf("%s", s);
1958c2ecf20Sopenharmony_ci	printf("\n#\n");
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void (*conf_message_callback)(const char *s) =
1998c2ecf20Sopenharmony_ci	conf_default_message_callback;
2008c2ecf20Sopenharmony_civoid conf_set_message_callback(void (*fn)(const char *s))
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	conf_message_callback = fn;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void conf_message(const char *fmt, ...)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	va_list ap;
2088c2ecf20Sopenharmony_ci	char buf[4096];
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!conf_message_callback)
2118c2ecf20Sopenharmony_ci		return;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	va_start(ap, fmt);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, ap);
2168c2ecf20Sopenharmony_ci	conf_message_callback(buf);
2178c2ecf20Sopenharmony_ci	va_end(ap);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciconst char *conf_get_configname(void)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	char *name = getenv("KCONFIG_CONFIG");
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return name ? name : ".config";
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic const char *conf_get_autoconfig_name(void)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	char *name = getenv("KCONFIG_AUTOCONFIG");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return name ? name : "include/config/auto.conf";
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	char *p2;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	switch (sym->type) {
2398c2ecf20Sopenharmony_ci	case S_TRISTATE:
2408c2ecf20Sopenharmony_ci		if (p[0] == 'm') {
2418c2ecf20Sopenharmony_ci			sym->def[def].tri = mod;
2428c2ecf20Sopenharmony_ci			sym->flags |= def_flags;
2438c2ecf20Sopenharmony_ci			break;
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci		/* fall through */
2468c2ecf20Sopenharmony_ci	case S_BOOLEAN:
2478c2ecf20Sopenharmony_ci		if (p[0] == 'y') {
2488c2ecf20Sopenharmony_ci			sym->def[def].tri = yes;
2498c2ecf20Sopenharmony_ci			sym->flags |= def_flags;
2508c2ecf20Sopenharmony_ci			break;
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci		if (p[0] == 'n') {
2538c2ecf20Sopenharmony_ci			sym->def[def].tri = no;
2548c2ecf20Sopenharmony_ci			sym->flags |= def_flags;
2558c2ecf20Sopenharmony_ci			break;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci		if (def != S_DEF_AUTO)
2588c2ecf20Sopenharmony_ci			conf_warning("symbol value '%s' invalid for %s",
2598c2ecf20Sopenharmony_ci				     p, sym->name);
2608c2ecf20Sopenharmony_ci		return 1;
2618c2ecf20Sopenharmony_ci	case S_STRING:
2628c2ecf20Sopenharmony_ci		if (*p++ != '"')
2638c2ecf20Sopenharmony_ci			break;
2648c2ecf20Sopenharmony_ci		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
2658c2ecf20Sopenharmony_ci			if (*p2 == '"') {
2668c2ecf20Sopenharmony_ci				*p2 = 0;
2678c2ecf20Sopenharmony_ci				break;
2688c2ecf20Sopenharmony_ci			}
2698c2ecf20Sopenharmony_ci			memmove(p2, p2 + 1, strlen(p2));
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci		if (!p2) {
2728c2ecf20Sopenharmony_ci			if (def != S_DEF_AUTO)
2738c2ecf20Sopenharmony_ci				conf_warning("invalid string found");
2748c2ecf20Sopenharmony_ci			return 1;
2758c2ecf20Sopenharmony_ci		}
2768c2ecf20Sopenharmony_ci		/* fall through */
2778c2ecf20Sopenharmony_ci	case S_INT:
2788c2ecf20Sopenharmony_ci	case S_HEX:
2798c2ecf20Sopenharmony_ci		if (sym_string_valid(sym, p)) {
2808c2ecf20Sopenharmony_ci			sym->def[def].val = xstrdup(p);
2818c2ecf20Sopenharmony_ci			sym->flags |= def_flags;
2828c2ecf20Sopenharmony_ci		} else {
2838c2ecf20Sopenharmony_ci			if (def != S_DEF_AUTO)
2848c2ecf20Sopenharmony_ci				conf_warning("symbol value '%s' invalid for %s",
2858c2ecf20Sopenharmony_ci					     p, sym->name);
2868c2ecf20Sopenharmony_ci			return 1;
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci		break;
2898c2ecf20Sopenharmony_ci	default:
2908c2ecf20Sopenharmony_ci		;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	return 0;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci#define LINE_GROWTH 16
2968c2ecf20Sopenharmony_cistatic int add_byte(int c, char **lineptr, size_t slen, size_t *n)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	char *nline;
2998c2ecf20Sopenharmony_ci	size_t new_size = slen + 1;
3008c2ecf20Sopenharmony_ci	if (new_size > *n) {
3018c2ecf20Sopenharmony_ci		new_size += LINE_GROWTH - 1;
3028c2ecf20Sopenharmony_ci		new_size *= 2;
3038c2ecf20Sopenharmony_ci		nline = xrealloc(*lineptr, new_size);
3048c2ecf20Sopenharmony_ci		if (!nline)
3058c2ecf20Sopenharmony_ci			return -1;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		*lineptr = nline;
3088c2ecf20Sopenharmony_ci		*n = new_size;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	(*lineptr)[slen] = c;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return 0;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	char *line = *lineptr;
3198c2ecf20Sopenharmony_ci	size_t slen = 0;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	for (;;) {
3228c2ecf20Sopenharmony_ci		int c = getc(stream);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		switch (c) {
3258c2ecf20Sopenharmony_ci		case '\n':
3268c2ecf20Sopenharmony_ci			if (add_byte(c, &line, slen, n) < 0)
3278c2ecf20Sopenharmony_ci				goto e_out;
3288c2ecf20Sopenharmony_ci			slen++;
3298c2ecf20Sopenharmony_ci			/* fall through */
3308c2ecf20Sopenharmony_ci		case EOF:
3318c2ecf20Sopenharmony_ci			if (add_byte('\0', &line, slen, n) < 0)
3328c2ecf20Sopenharmony_ci				goto e_out;
3338c2ecf20Sopenharmony_ci			*lineptr = line;
3348c2ecf20Sopenharmony_ci			if (slen == 0)
3358c2ecf20Sopenharmony_ci				return -1;
3368c2ecf20Sopenharmony_ci			return slen;
3378c2ecf20Sopenharmony_ci		default:
3388c2ecf20Sopenharmony_ci			if (add_byte(c, &line, slen, n) < 0)
3398c2ecf20Sopenharmony_ci				goto e_out;
3408c2ecf20Sopenharmony_ci			slen++;
3418c2ecf20Sopenharmony_ci		}
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cie_out:
3458c2ecf20Sopenharmony_ci	line[slen-1] = '\0';
3468c2ecf20Sopenharmony_ci	*lineptr = line;
3478c2ecf20Sopenharmony_ci	return -1;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ciint conf_read_simple(const char *name, int def)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	FILE *in = NULL;
3538c2ecf20Sopenharmony_ci	char   *line = NULL;
3548c2ecf20Sopenharmony_ci	size_t  line_asize = 0;
3558c2ecf20Sopenharmony_ci	char *p, *p2;
3568c2ecf20Sopenharmony_ci	struct symbol *sym;
3578c2ecf20Sopenharmony_ci	int i, def_flags;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (name) {
3608c2ecf20Sopenharmony_ci		in = zconf_fopen(name);
3618c2ecf20Sopenharmony_ci	} else {
3628c2ecf20Sopenharmony_ci		struct property *prop;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		name = conf_get_configname();
3658c2ecf20Sopenharmony_ci		in = zconf_fopen(name);
3668c2ecf20Sopenharmony_ci		if (in)
3678c2ecf20Sopenharmony_ci			goto load;
3688c2ecf20Sopenharmony_ci		sym_add_change_count(1);
3698c2ecf20Sopenharmony_ci		if (!sym_defconfig_list)
3708c2ecf20Sopenharmony_ci			return 1;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		for_all_defaults(sym_defconfig_list, prop) {
3738c2ecf20Sopenharmony_ci			if (expr_calc_value(prop->visible.expr) == no ||
3748c2ecf20Sopenharmony_ci			    prop->expr->type != E_SYMBOL)
3758c2ecf20Sopenharmony_ci				continue;
3768c2ecf20Sopenharmony_ci			sym_calc_value(prop->expr->left.sym);
3778c2ecf20Sopenharmony_ci			name = sym_get_string_value(prop->expr->left.sym);
3788c2ecf20Sopenharmony_ci			in = zconf_fopen(name);
3798c2ecf20Sopenharmony_ci			if (in) {
3808c2ecf20Sopenharmony_ci				conf_message("using defaults found in %s",
3818c2ecf20Sopenharmony_ci					 name);
3828c2ecf20Sopenharmony_ci				goto load;
3838c2ecf20Sopenharmony_ci			}
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	if (!in)
3878c2ecf20Sopenharmony_ci		return 1;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciload:
3908c2ecf20Sopenharmony_ci	conf_filename = name;
3918c2ecf20Sopenharmony_ci	conf_lineno = 0;
3928c2ecf20Sopenharmony_ci	conf_warnings = 0;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	def_flags = SYMBOL_DEF << def;
3958c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
3968c2ecf20Sopenharmony_ci		sym->flags |= SYMBOL_CHANGED;
3978c2ecf20Sopenharmony_ci		sym->flags &= ~(def_flags|SYMBOL_VALID);
3988c2ecf20Sopenharmony_ci		if (sym_is_choice(sym))
3998c2ecf20Sopenharmony_ci			sym->flags |= def_flags;
4008c2ecf20Sopenharmony_ci		switch (sym->type) {
4018c2ecf20Sopenharmony_ci		case S_INT:
4028c2ecf20Sopenharmony_ci		case S_HEX:
4038c2ecf20Sopenharmony_ci		case S_STRING:
4048c2ecf20Sopenharmony_ci			if (sym->def[def].val)
4058c2ecf20Sopenharmony_ci				free(sym->def[def].val);
4068c2ecf20Sopenharmony_ci			/* fall through */
4078c2ecf20Sopenharmony_ci		default:
4088c2ecf20Sopenharmony_ci			sym->def[def].val = NULL;
4098c2ecf20Sopenharmony_ci			sym->def[def].tri = no;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	while (compat_getline(&line, &line_asize, in) != -1) {
4148c2ecf20Sopenharmony_ci		conf_lineno++;
4158c2ecf20Sopenharmony_ci		sym = NULL;
4168c2ecf20Sopenharmony_ci		if (line[0] == '#') {
4178c2ecf20Sopenharmony_ci			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
4188c2ecf20Sopenharmony_ci				continue;
4198c2ecf20Sopenharmony_ci			p = strchr(line + 2 + strlen(CONFIG_), ' ');
4208c2ecf20Sopenharmony_ci			if (!p)
4218c2ecf20Sopenharmony_ci				continue;
4228c2ecf20Sopenharmony_ci			*p++ = 0;
4238c2ecf20Sopenharmony_ci			if (strncmp(p, "is not set", 10))
4248c2ecf20Sopenharmony_ci				continue;
4258c2ecf20Sopenharmony_ci			if (def == S_DEF_USER) {
4268c2ecf20Sopenharmony_ci				sym = sym_find(line + 2 + strlen(CONFIG_));
4278c2ecf20Sopenharmony_ci				if (!sym) {
4288c2ecf20Sopenharmony_ci					sym_add_change_count(1);
4298c2ecf20Sopenharmony_ci					continue;
4308c2ecf20Sopenharmony_ci				}
4318c2ecf20Sopenharmony_ci			} else {
4328c2ecf20Sopenharmony_ci				sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
4338c2ecf20Sopenharmony_ci				if (sym->type == S_UNKNOWN)
4348c2ecf20Sopenharmony_ci					sym->type = S_BOOLEAN;
4358c2ecf20Sopenharmony_ci			}
4368c2ecf20Sopenharmony_ci			if (sym->flags & def_flags) {
4378c2ecf20Sopenharmony_ci				conf_warning("override: reassigning to symbol %s", sym->name);
4388c2ecf20Sopenharmony_ci			}
4398c2ecf20Sopenharmony_ci			switch (sym->type) {
4408c2ecf20Sopenharmony_ci			case S_BOOLEAN:
4418c2ecf20Sopenharmony_ci			case S_TRISTATE:
4428c2ecf20Sopenharmony_ci				sym->def[def].tri = no;
4438c2ecf20Sopenharmony_ci				sym->flags |= def_flags;
4448c2ecf20Sopenharmony_ci				break;
4458c2ecf20Sopenharmony_ci			default:
4468c2ecf20Sopenharmony_ci				;
4478c2ecf20Sopenharmony_ci			}
4488c2ecf20Sopenharmony_ci		} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
4498c2ecf20Sopenharmony_ci			p = strchr(line + strlen(CONFIG_), '=');
4508c2ecf20Sopenharmony_ci			if (!p)
4518c2ecf20Sopenharmony_ci				continue;
4528c2ecf20Sopenharmony_ci			*p++ = 0;
4538c2ecf20Sopenharmony_ci			p2 = strchr(p, '\n');
4548c2ecf20Sopenharmony_ci			if (p2) {
4558c2ecf20Sopenharmony_ci				*p2-- = 0;
4568c2ecf20Sopenharmony_ci				if (*p2 == '\r')
4578c2ecf20Sopenharmony_ci					*p2 = 0;
4588c2ecf20Sopenharmony_ci			}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci			sym = sym_find(line + strlen(CONFIG_));
4618c2ecf20Sopenharmony_ci			if (!sym) {
4628c2ecf20Sopenharmony_ci				if (def == S_DEF_AUTO)
4638c2ecf20Sopenharmony_ci					/*
4648c2ecf20Sopenharmony_ci					 * Reading from include/config/auto.conf
4658c2ecf20Sopenharmony_ci					 * If CONFIG_FOO previously existed in
4668c2ecf20Sopenharmony_ci					 * auto.conf but it is missing now,
4678c2ecf20Sopenharmony_ci					 * include/config/foo.h must be touched.
4688c2ecf20Sopenharmony_ci					 */
4698c2ecf20Sopenharmony_ci					conf_touch_dep(line + strlen(CONFIG_));
4708c2ecf20Sopenharmony_ci				else
4718c2ecf20Sopenharmony_ci					sym_add_change_count(1);
4728c2ecf20Sopenharmony_ci				continue;
4738c2ecf20Sopenharmony_ci			}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci			if (sym->flags & def_flags) {
4768c2ecf20Sopenharmony_ci				conf_warning("override: reassigning to symbol %s", sym->name);
4778c2ecf20Sopenharmony_ci			}
4788c2ecf20Sopenharmony_ci			if (conf_set_sym_val(sym, def, def_flags, p))
4798c2ecf20Sopenharmony_ci				continue;
4808c2ecf20Sopenharmony_ci		} else {
4818c2ecf20Sopenharmony_ci			if (line[0] != '\r' && line[0] != '\n')
4828c2ecf20Sopenharmony_ci				conf_warning("unexpected data: %.*s",
4838c2ecf20Sopenharmony_ci					     (int)strcspn(line, "\r\n"), line);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci			continue;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		if (sym && sym_is_choice_value(sym)) {
4898c2ecf20Sopenharmony_ci			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
4908c2ecf20Sopenharmony_ci			switch (sym->def[def].tri) {
4918c2ecf20Sopenharmony_ci			case no:
4928c2ecf20Sopenharmony_ci				break;
4938c2ecf20Sopenharmony_ci			case mod:
4948c2ecf20Sopenharmony_ci				if (cs->def[def].tri == yes) {
4958c2ecf20Sopenharmony_ci					conf_warning("%s creates inconsistent choice state", sym->name);
4968c2ecf20Sopenharmony_ci					cs->flags &= ~def_flags;
4978c2ecf20Sopenharmony_ci				}
4988c2ecf20Sopenharmony_ci				break;
4998c2ecf20Sopenharmony_ci			case yes:
5008c2ecf20Sopenharmony_ci				if (cs->def[def].tri != no)
5018c2ecf20Sopenharmony_ci					conf_warning("override: %s changes choice state", sym->name);
5028c2ecf20Sopenharmony_ci				cs->def[def].val = sym;
5038c2ecf20Sopenharmony_ci				break;
5048c2ecf20Sopenharmony_ci			}
5058c2ecf20Sopenharmony_ci			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
5068c2ecf20Sopenharmony_ci		}
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci	free(line);
5098c2ecf20Sopenharmony_ci	fclose(in);
5108c2ecf20Sopenharmony_ci	return 0;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ciint conf_read(const char *name)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct symbol *sym;
5168c2ecf20Sopenharmony_ci	int conf_unsaved = 0;
5178c2ecf20Sopenharmony_ci	int i;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	sym_set_change_count(0);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (conf_read_simple(name, S_DEF_USER)) {
5228c2ecf20Sopenharmony_ci		sym_calc_value(modules_sym);
5238c2ecf20Sopenharmony_ci		return 1;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	sym_calc_value(modules_sym);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
5298c2ecf20Sopenharmony_ci		sym_calc_value(sym);
5308c2ecf20Sopenharmony_ci		if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
5318c2ecf20Sopenharmony_ci			continue;
5328c2ecf20Sopenharmony_ci		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
5338c2ecf20Sopenharmony_ci			/* check that calculated value agrees with saved value */
5348c2ecf20Sopenharmony_ci			switch (sym->type) {
5358c2ecf20Sopenharmony_ci			case S_BOOLEAN:
5368c2ecf20Sopenharmony_ci			case S_TRISTATE:
5378c2ecf20Sopenharmony_ci				if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
5388c2ecf20Sopenharmony_ci					continue;
5398c2ecf20Sopenharmony_ci				break;
5408c2ecf20Sopenharmony_ci			default:
5418c2ecf20Sopenharmony_ci				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
5428c2ecf20Sopenharmony_ci					continue;
5438c2ecf20Sopenharmony_ci				break;
5448c2ecf20Sopenharmony_ci			}
5458c2ecf20Sopenharmony_ci		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
5468c2ecf20Sopenharmony_ci			/* no previous value and not saved */
5478c2ecf20Sopenharmony_ci			continue;
5488c2ecf20Sopenharmony_ci		conf_unsaved++;
5498c2ecf20Sopenharmony_ci		/* maybe print value in verbose mode... */
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
5538c2ecf20Sopenharmony_ci		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
5548c2ecf20Sopenharmony_ci			/* Reset values of generates values, so they'll appear
5558c2ecf20Sopenharmony_ci			 * as new, if they should become visible, but that
5568c2ecf20Sopenharmony_ci			 * doesn't quite work if the Kconfig and the saved
5578c2ecf20Sopenharmony_ci			 * configuration disagree.
5588c2ecf20Sopenharmony_ci			 */
5598c2ecf20Sopenharmony_ci			if (sym->visible == no && !conf_unsaved)
5608c2ecf20Sopenharmony_ci				sym->flags &= ~SYMBOL_DEF_USER;
5618c2ecf20Sopenharmony_ci			switch (sym->type) {
5628c2ecf20Sopenharmony_ci			case S_STRING:
5638c2ecf20Sopenharmony_ci			case S_INT:
5648c2ecf20Sopenharmony_ci			case S_HEX:
5658c2ecf20Sopenharmony_ci				/* Reset a string value if it's out of range */
5668c2ecf20Sopenharmony_ci				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
5678c2ecf20Sopenharmony_ci					break;
5688c2ecf20Sopenharmony_ci				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
5698c2ecf20Sopenharmony_ci				conf_unsaved++;
5708c2ecf20Sopenharmony_ci				break;
5718c2ecf20Sopenharmony_ci			default:
5728c2ecf20Sopenharmony_ci				break;
5738c2ecf20Sopenharmony_ci			}
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	sym_add_change_count(conf_warnings || conf_unsaved);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci/*
5838c2ecf20Sopenharmony_ci * Kconfig configuration printer
5848c2ecf20Sopenharmony_ci *
5858c2ecf20Sopenharmony_ci * This printer is used when generating the resulting configuration after
5868c2ecf20Sopenharmony_ci * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
5878c2ecf20Sopenharmony_ci * passing a non-NULL argument to the printer.
5888c2ecf20Sopenharmony_ci *
5898c2ecf20Sopenharmony_ci */
5908c2ecf20Sopenharmony_cistatic void
5918c2ecf20Sopenharmony_cikconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	switch (sym->type) {
5958c2ecf20Sopenharmony_ci	case S_BOOLEAN:
5968c2ecf20Sopenharmony_ci	case S_TRISTATE:
5978c2ecf20Sopenharmony_ci		if (*value == 'n') {
5988c2ecf20Sopenharmony_ci			bool skip_unset = (arg != NULL);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			if (!skip_unset)
6018c2ecf20Sopenharmony_ci				fprintf(fp, "# %s%s is not set\n",
6028c2ecf20Sopenharmony_ci				    CONFIG_, sym->name);
6038c2ecf20Sopenharmony_ci			return;
6048c2ecf20Sopenharmony_ci		}
6058c2ecf20Sopenharmony_ci		break;
6068c2ecf20Sopenharmony_ci	default:
6078c2ecf20Sopenharmony_ci		break;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic void
6148c2ecf20Sopenharmony_cikconfig_print_comment(FILE *fp, const char *value, void *arg)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	const char *p = value;
6178c2ecf20Sopenharmony_ci	size_t l;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	for (;;) {
6208c2ecf20Sopenharmony_ci		l = strcspn(p, "\n");
6218c2ecf20Sopenharmony_ci		fprintf(fp, "#");
6228c2ecf20Sopenharmony_ci		if (l) {
6238c2ecf20Sopenharmony_ci			fprintf(fp, " ");
6248c2ecf20Sopenharmony_ci			xfwrite(p, l, 1, fp);
6258c2ecf20Sopenharmony_ci			p += l;
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci		fprintf(fp, "\n");
6288c2ecf20Sopenharmony_ci		if (*p++ == '\0')
6298c2ecf20Sopenharmony_ci			break;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic struct conf_printer kconfig_printer_cb =
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	.print_symbol = kconfig_print_symbol,
6368c2ecf20Sopenharmony_ci	.print_comment = kconfig_print_comment,
6378c2ecf20Sopenharmony_ci};
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci/*
6408c2ecf20Sopenharmony_ci * Header printer
6418c2ecf20Sopenharmony_ci *
6428c2ecf20Sopenharmony_ci * This printer is used when generating the `include/generated/autoconf.h' file.
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_cistatic void
6458c2ecf20Sopenharmony_ciheader_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	switch (sym->type) {
6498c2ecf20Sopenharmony_ci	case S_BOOLEAN:
6508c2ecf20Sopenharmony_ci	case S_TRISTATE: {
6518c2ecf20Sopenharmony_ci		const char *suffix = "";
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		switch (*value) {
6548c2ecf20Sopenharmony_ci		case 'n':
6558c2ecf20Sopenharmony_ci			break;
6568c2ecf20Sopenharmony_ci		case 'm':
6578c2ecf20Sopenharmony_ci			suffix = "_MODULE";
6588c2ecf20Sopenharmony_ci			/* fall through */
6598c2ecf20Sopenharmony_ci		default:
6608c2ecf20Sopenharmony_ci			fprintf(fp, "#define %s%s%s 1\n",
6618c2ecf20Sopenharmony_ci			    CONFIG_, sym->name, suffix);
6628c2ecf20Sopenharmony_ci		}
6638c2ecf20Sopenharmony_ci		break;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci	case S_HEX: {
6668c2ecf20Sopenharmony_ci		const char *prefix = "";
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
6698c2ecf20Sopenharmony_ci			prefix = "0x";
6708c2ecf20Sopenharmony_ci		fprintf(fp, "#define %s%s %s%s\n",
6718c2ecf20Sopenharmony_ci		    CONFIG_, sym->name, prefix, value);
6728c2ecf20Sopenharmony_ci		break;
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci	case S_STRING:
6758c2ecf20Sopenharmony_ci	case S_INT:
6768c2ecf20Sopenharmony_ci		fprintf(fp, "#define %s%s %s\n",
6778c2ecf20Sopenharmony_ci		    CONFIG_, sym->name, value);
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci	default:
6808c2ecf20Sopenharmony_ci		break;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic void
6868c2ecf20Sopenharmony_ciheader_print_comment(FILE *fp, const char *value, void *arg)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	const char *p = value;
6898c2ecf20Sopenharmony_ci	size_t l;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	fprintf(fp, "/*\n");
6928c2ecf20Sopenharmony_ci	for (;;) {
6938c2ecf20Sopenharmony_ci		l = strcspn(p, "\n");
6948c2ecf20Sopenharmony_ci		fprintf(fp, " *");
6958c2ecf20Sopenharmony_ci		if (l) {
6968c2ecf20Sopenharmony_ci			fprintf(fp, " ");
6978c2ecf20Sopenharmony_ci			xfwrite(p, l, 1, fp);
6988c2ecf20Sopenharmony_ci			p += l;
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci		fprintf(fp, "\n");
7018c2ecf20Sopenharmony_ci		if (*p++ == '\0')
7028c2ecf20Sopenharmony_ci			break;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci	fprintf(fp, " */\n");
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic struct conf_printer header_printer_cb =
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	.print_symbol = header_print_symbol,
7108c2ecf20Sopenharmony_ci	.print_comment = header_print_comment,
7118c2ecf20Sopenharmony_ci};
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic void conf_write_symbol(FILE *fp, struct symbol *sym,
7148c2ecf20Sopenharmony_ci			      struct conf_printer *printer, void *printer_arg)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	const char *str;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	switch (sym->type) {
7198c2ecf20Sopenharmony_ci	case S_UNKNOWN:
7208c2ecf20Sopenharmony_ci		break;
7218c2ecf20Sopenharmony_ci	case S_STRING:
7228c2ecf20Sopenharmony_ci		str = sym_get_string_value(sym);
7238c2ecf20Sopenharmony_ci		str = sym_escape_string_value(str);
7248c2ecf20Sopenharmony_ci		printer->print_symbol(fp, sym, str, printer_arg);
7258c2ecf20Sopenharmony_ci		free((void *)str);
7268c2ecf20Sopenharmony_ci		break;
7278c2ecf20Sopenharmony_ci	default:
7288c2ecf20Sopenharmony_ci		str = sym_get_string_value(sym);
7298c2ecf20Sopenharmony_ci		printer->print_symbol(fp, sym, str, printer_arg);
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic void
7348c2ecf20Sopenharmony_ciconf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	char buf[256];
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf),
7398c2ecf20Sopenharmony_ci	    "\n"
7408c2ecf20Sopenharmony_ci	    "Automatically generated file; DO NOT EDIT.\n"
7418c2ecf20Sopenharmony_ci	    "%s\n",
7428c2ecf20Sopenharmony_ci	    rootmenu.prompt->text);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	printer->print_comment(fp, buf, printer_arg);
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci/*
7488c2ecf20Sopenharmony_ci * Write out a minimal config.
7498c2ecf20Sopenharmony_ci * All values that has default values are skipped as this is redundant.
7508c2ecf20Sopenharmony_ci */
7518c2ecf20Sopenharmony_ciint conf_write_defconfig(const char *filename)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct symbol *sym;
7548c2ecf20Sopenharmony_ci	struct menu *menu;
7558c2ecf20Sopenharmony_ci	FILE *out;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	out = fopen(filename, "w");
7588c2ecf20Sopenharmony_ci	if (!out)
7598c2ecf20Sopenharmony_ci		return 1;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	sym_clear_all_valid();
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Traverse all menus to find all relevant symbols */
7648c2ecf20Sopenharmony_ci	menu = rootmenu.list;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	while (menu != NULL)
7678c2ecf20Sopenharmony_ci	{
7688c2ecf20Sopenharmony_ci		sym = menu->sym;
7698c2ecf20Sopenharmony_ci		if (sym == NULL) {
7708c2ecf20Sopenharmony_ci			if (!menu_is_visible(menu))
7718c2ecf20Sopenharmony_ci				goto next_menu;
7728c2ecf20Sopenharmony_ci		} else if (!sym_is_choice(sym)) {
7738c2ecf20Sopenharmony_ci			sym_calc_value(sym);
7748c2ecf20Sopenharmony_ci			if (!(sym->flags & SYMBOL_WRITE))
7758c2ecf20Sopenharmony_ci				goto next_menu;
7768c2ecf20Sopenharmony_ci			sym->flags &= ~SYMBOL_WRITE;
7778c2ecf20Sopenharmony_ci			/* If we cannot change the symbol - skip */
7788c2ecf20Sopenharmony_ci			if (!sym_is_changeable(sym))
7798c2ecf20Sopenharmony_ci				goto next_menu;
7808c2ecf20Sopenharmony_ci			/* If symbol equals to default value - skip */
7818c2ecf20Sopenharmony_ci			if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
7828c2ecf20Sopenharmony_ci				goto next_menu;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci			/*
7858c2ecf20Sopenharmony_ci			 * If symbol is a choice value and equals to the
7868c2ecf20Sopenharmony_ci			 * default for a choice - skip.
7878c2ecf20Sopenharmony_ci			 * But only if value is bool and equal to "y" and
7888c2ecf20Sopenharmony_ci			 * choice is not "optional".
7898c2ecf20Sopenharmony_ci			 * (If choice is "optional" then all values can be "n")
7908c2ecf20Sopenharmony_ci			 */
7918c2ecf20Sopenharmony_ci			if (sym_is_choice_value(sym)) {
7928c2ecf20Sopenharmony_ci				struct symbol *cs;
7938c2ecf20Sopenharmony_ci				struct symbol *ds;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci				cs = prop_get_symbol(sym_get_choice_prop(sym));
7968c2ecf20Sopenharmony_ci				ds = sym_choice_default(cs);
7978c2ecf20Sopenharmony_ci				if (!sym_is_optional(cs) && sym == ds) {
7988c2ecf20Sopenharmony_ci					if ((sym->type == S_BOOLEAN) &&
7998c2ecf20Sopenharmony_ci					    sym_get_tristate_value(sym) == yes)
8008c2ecf20Sopenharmony_ci						goto next_menu;
8018c2ecf20Sopenharmony_ci				}
8028c2ecf20Sopenharmony_ci			}
8038c2ecf20Sopenharmony_ci			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
8048c2ecf20Sopenharmony_ci		}
8058c2ecf20Sopenharmony_cinext_menu:
8068c2ecf20Sopenharmony_ci		if (menu->list != NULL) {
8078c2ecf20Sopenharmony_ci			menu = menu->list;
8088c2ecf20Sopenharmony_ci		}
8098c2ecf20Sopenharmony_ci		else if (menu->next != NULL) {
8108c2ecf20Sopenharmony_ci			menu = menu->next;
8118c2ecf20Sopenharmony_ci		} else {
8128c2ecf20Sopenharmony_ci			while ((menu = menu->parent)) {
8138c2ecf20Sopenharmony_ci				if (menu->next != NULL) {
8148c2ecf20Sopenharmony_ci					menu = menu->next;
8158c2ecf20Sopenharmony_ci					break;
8168c2ecf20Sopenharmony_ci				}
8178c2ecf20Sopenharmony_ci			}
8188c2ecf20Sopenharmony_ci		}
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci	fclose(out);
8218c2ecf20Sopenharmony_ci	return 0;
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ciint conf_write(const char *name)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	FILE *out;
8278c2ecf20Sopenharmony_ci	struct symbol *sym;
8288c2ecf20Sopenharmony_ci	struct menu *menu;
8298c2ecf20Sopenharmony_ci	const char *str;
8308c2ecf20Sopenharmony_ci	char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
8318c2ecf20Sopenharmony_ci	char *env;
8328c2ecf20Sopenharmony_ci	int i;
8338c2ecf20Sopenharmony_ci	bool need_newline = false;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	if (!name)
8368c2ecf20Sopenharmony_ci		name = conf_get_configname();
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (!*name) {
8398c2ecf20Sopenharmony_ci		fprintf(stderr, "config name is empty\n");
8408c2ecf20Sopenharmony_ci		return -1;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	if (is_dir(name)) {
8448c2ecf20Sopenharmony_ci		fprintf(stderr, "%s: Is a directory\n", name);
8458c2ecf20Sopenharmony_ci		return -1;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (make_parent_dir(name))
8498c2ecf20Sopenharmony_ci		return -1;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	env = getenv("KCONFIG_OVERWRITECONFIG");
8528c2ecf20Sopenharmony_ci	if (env && *env) {
8538c2ecf20Sopenharmony_ci		*tmpname = 0;
8548c2ecf20Sopenharmony_ci		out = fopen(name, "w");
8558c2ecf20Sopenharmony_ci	} else {
8568c2ecf20Sopenharmony_ci		snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
8578c2ecf20Sopenharmony_ci			 name, (int)getpid());
8588c2ecf20Sopenharmony_ci		out = fopen(tmpname, "w");
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci	if (!out)
8618c2ecf20Sopenharmony_ci		return 1;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	conf_write_heading(out, &kconfig_printer_cb, NULL);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	if (!conf_get_changed())
8668c2ecf20Sopenharmony_ci		sym_clear_all_valid();
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	menu = rootmenu.list;
8698c2ecf20Sopenharmony_ci	while (menu) {
8708c2ecf20Sopenharmony_ci		sym = menu->sym;
8718c2ecf20Sopenharmony_ci		if (!sym) {
8728c2ecf20Sopenharmony_ci			if (!menu_is_visible(menu))
8738c2ecf20Sopenharmony_ci				goto next;
8748c2ecf20Sopenharmony_ci			str = menu_get_prompt(menu);
8758c2ecf20Sopenharmony_ci			fprintf(out, "\n"
8768c2ecf20Sopenharmony_ci				     "#\n"
8778c2ecf20Sopenharmony_ci				     "# %s\n"
8788c2ecf20Sopenharmony_ci				     "#\n", str);
8798c2ecf20Sopenharmony_ci			need_newline = false;
8808c2ecf20Sopenharmony_ci		} else if (!(sym->flags & SYMBOL_CHOICE) &&
8818c2ecf20Sopenharmony_ci			   !(sym->flags & SYMBOL_WRITTEN)) {
8828c2ecf20Sopenharmony_ci			sym_calc_value(sym);
8838c2ecf20Sopenharmony_ci			if (!(sym->flags & SYMBOL_WRITE))
8848c2ecf20Sopenharmony_ci				goto next;
8858c2ecf20Sopenharmony_ci			if (need_newline) {
8868c2ecf20Sopenharmony_ci				fprintf(out, "\n");
8878c2ecf20Sopenharmony_ci				need_newline = false;
8888c2ecf20Sopenharmony_ci			}
8898c2ecf20Sopenharmony_ci			sym->flags |= SYMBOL_WRITTEN;
8908c2ecf20Sopenharmony_ci			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
8918c2ecf20Sopenharmony_ci		}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cinext:
8948c2ecf20Sopenharmony_ci		if (menu->list) {
8958c2ecf20Sopenharmony_ci			menu = menu->list;
8968c2ecf20Sopenharmony_ci			continue;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci		if (menu->next)
8998c2ecf20Sopenharmony_ci			menu = menu->next;
9008c2ecf20Sopenharmony_ci		else while ((menu = menu->parent)) {
9018c2ecf20Sopenharmony_ci			if (!menu->sym && menu_is_visible(menu) &&
9028c2ecf20Sopenharmony_ci			    menu != &rootmenu) {
9038c2ecf20Sopenharmony_ci				str = menu_get_prompt(menu);
9048c2ecf20Sopenharmony_ci				fprintf(out, "# end of %s\n", str);
9058c2ecf20Sopenharmony_ci				need_newline = true;
9068c2ecf20Sopenharmony_ci			}
9078c2ecf20Sopenharmony_ci			if (menu->next) {
9088c2ecf20Sopenharmony_ci				menu = menu->next;
9098c2ecf20Sopenharmony_ci				break;
9108c2ecf20Sopenharmony_ci			}
9118c2ecf20Sopenharmony_ci		}
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci	fclose(out);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	for_all_symbols(i, sym)
9168c2ecf20Sopenharmony_ci		sym->flags &= ~SYMBOL_WRITTEN;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (*tmpname) {
9198c2ecf20Sopenharmony_ci		if (is_same(name, tmpname)) {
9208c2ecf20Sopenharmony_ci			conf_message("No change to %s", name);
9218c2ecf20Sopenharmony_ci			unlink(tmpname);
9228c2ecf20Sopenharmony_ci			sym_set_change_count(0);
9238c2ecf20Sopenharmony_ci			return 0;
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		snprintf(oldname, sizeof(oldname), "%s.old", name);
9278c2ecf20Sopenharmony_ci		rename(name, oldname);
9288c2ecf20Sopenharmony_ci		if (rename(tmpname, name))
9298c2ecf20Sopenharmony_ci			return 1;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	conf_message("configuration written to %s", name);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	sym_set_change_count(0);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return 0;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci/* write a dependency file as used by kbuild to track dependencies */
9408c2ecf20Sopenharmony_cistatic int conf_write_dep(const char *name)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	struct file *file;
9438c2ecf20Sopenharmony_ci	FILE *out;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	out = fopen("..config.tmp", "w");
9468c2ecf20Sopenharmony_ci	if (!out)
9478c2ecf20Sopenharmony_ci		return 1;
9488c2ecf20Sopenharmony_ci	fprintf(out, "deps_config := \\\n");
9498c2ecf20Sopenharmony_ci	for (file = file_list; file; file = file->next) {
9508c2ecf20Sopenharmony_ci		if (file->next)
9518c2ecf20Sopenharmony_ci			fprintf(out, "\t%s \\\n", file->name);
9528c2ecf20Sopenharmony_ci		else
9538c2ecf20Sopenharmony_ci			fprintf(out, "\t%s\n", file->name);
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci	fprintf(out, "\n%s: \\\n"
9568c2ecf20Sopenharmony_ci		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	env_write_dep(out, conf_get_autoconfig_name());
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	fprintf(out, "\n$(deps_config): ;\n");
9618c2ecf20Sopenharmony_ci	fclose(out);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	if (make_parent_dir(name))
9648c2ecf20Sopenharmony_ci		return 1;
9658c2ecf20Sopenharmony_ci	rename("..config.tmp", name);
9668c2ecf20Sopenharmony_ci	return 0;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic int conf_touch_deps(void)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	const char *name, *tmp;
9728c2ecf20Sopenharmony_ci	struct symbol *sym;
9738c2ecf20Sopenharmony_ci	int res, i;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	name = conf_get_autoconfig_name();
9768c2ecf20Sopenharmony_ci	tmp = strrchr(name, '/');
9778c2ecf20Sopenharmony_ci	depfile_prefix_len = tmp ? tmp - name + 1 : 0;
9788c2ecf20Sopenharmony_ci	if (depfile_prefix_len + 1 > sizeof(depfile_path))
9798c2ecf20Sopenharmony_ci		return -1;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	strncpy(depfile_path, name, depfile_prefix_len);
9828c2ecf20Sopenharmony_ci	depfile_path[depfile_prefix_len] = 0;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	conf_read_simple(name, S_DEF_AUTO);
9858c2ecf20Sopenharmony_ci	sym_calc_value(modules_sym);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
9888c2ecf20Sopenharmony_ci		sym_calc_value(sym);
9898c2ecf20Sopenharmony_ci		if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
9908c2ecf20Sopenharmony_ci			continue;
9918c2ecf20Sopenharmony_ci		if (sym->flags & SYMBOL_WRITE) {
9928c2ecf20Sopenharmony_ci			if (sym->flags & SYMBOL_DEF_AUTO) {
9938c2ecf20Sopenharmony_ci				/*
9948c2ecf20Sopenharmony_ci				 * symbol has old and new value,
9958c2ecf20Sopenharmony_ci				 * so compare them...
9968c2ecf20Sopenharmony_ci				 */
9978c2ecf20Sopenharmony_ci				switch (sym->type) {
9988c2ecf20Sopenharmony_ci				case S_BOOLEAN:
9998c2ecf20Sopenharmony_ci				case S_TRISTATE:
10008c2ecf20Sopenharmony_ci					if (sym_get_tristate_value(sym) ==
10018c2ecf20Sopenharmony_ci					    sym->def[S_DEF_AUTO].tri)
10028c2ecf20Sopenharmony_ci						continue;
10038c2ecf20Sopenharmony_ci					break;
10048c2ecf20Sopenharmony_ci				case S_STRING:
10058c2ecf20Sopenharmony_ci				case S_HEX:
10068c2ecf20Sopenharmony_ci				case S_INT:
10078c2ecf20Sopenharmony_ci					if (!strcmp(sym_get_string_value(sym),
10088c2ecf20Sopenharmony_ci						    sym->def[S_DEF_AUTO].val))
10098c2ecf20Sopenharmony_ci						continue;
10108c2ecf20Sopenharmony_ci					break;
10118c2ecf20Sopenharmony_ci				default:
10128c2ecf20Sopenharmony_ci					break;
10138c2ecf20Sopenharmony_ci				}
10148c2ecf20Sopenharmony_ci			} else {
10158c2ecf20Sopenharmony_ci				/*
10168c2ecf20Sopenharmony_ci				 * If there is no old value, only 'no' (unset)
10178c2ecf20Sopenharmony_ci				 * is allowed as new value.
10188c2ecf20Sopenharmony_ci				 */
10198c2ecf20Sopenharmony_ci				switch (sym->type) {
10208c2ecf20Sopenharmony_ci				case S_BOOLEAN:
10218c2ecf20Sopenharmony_ci				case S_TRISTATE:
10228c2ecf20Sopenharmony_ci					if (sym_get_tristate_value(sym) == no)
10238c2ecf20Sopenharmony_ci						continue;
10248c2ecf20Sopenharmony_ci					break;
10258c2ecf20Sopenharmony_ci				default:
10268c2ecf20Sopenharmony_ci					break;
10278c2ecf20Sopenharmony_ci				}
10288c2ecf20Sopenharmony_ci			}
10298c2ecf20Sopenharmony_ci		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
10308c2ecf20Sopenharmony_ci			/* There is neither an old nor a new value. */
10318c2ecf20Sopenharmony_ci			continue;
10328c2ecf20Sopenharmony_ci		/* else
10338c2ecf20Sopenharmony_ci		 *	There is an old value, but no new value ('no' (unset)
10348c2ecf20Sopenharmony_ci		 *	isn't saved in auto.conf, so the old value is always
10358c2ecf20Sopenharmony_ci		 *	different from 'no').
10368c2ecf20Sopenharmony_ci		 */
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		res = conf_touch_dep(sym->name);
10398c2ecf20Sopenharmony_ci		if (res)
10408c2ecf20Sopenharmony_ci			return res;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	return 0;
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ciint conf_write_autoconf(int overwrite)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct symbol *sym;
10498c2ecf20Sopenharmony_ci	const char *name;
10508c2ecf20Sopenharmony_ci	const char *autoconf_name = conf_get_autoconfig_name();
10518c2ecf20Sopenharmony_ci	FILE *out, *out_h;
10528c2ecf20Sopenharmony_ci	int i;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if (!overwrite && is_present(autoconf_name))
10558c2ecf20Sopenharmony_ci		return 0;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	conf_write_dep("include/config/auto.conf.cmd");
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (conf_touch_deps())
10608c2ecf20Sopenharmony_ci		return 1;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	out = fopen(".tmpconfig", "w");
10638c2ecf20Sopenharmony_ci	if (!out)
10648c2ecf20Sopenharmony_ci		return 1;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	out_h = fopen(".tmpconfig.h", "w");
10678c2ecf20Sopenharmony_ci	if (!out_h) {
10688c2ecf20Sopenharmony_ci		fclose(out);
10698c2ecf20Sopenharmony_ci		return 1;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	conf_write_heading(out, &kconfig_printer_cb, NULL);
10738c2ecf20Sopenharmony_ci	conf_write_heading(out_h, &header_printer_cb, NULL);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
10768c2ecf20Sopenharmony_ci		sym_calc_value(sym);
10778c2ecf20Sopenharmony_ci		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
10788c2ecf20Sopenharmony_ci			continue;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		/* write symbols to auto.conf and autoconf.h */
10818c2ecf20Sopenharmony_ci		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
10828c2ecf20Sopenharmony_ci		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci	fclose(out);
10858c2ecf20Sopenharmony_ci	fclose(out_h);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	name = getenv("KCONFIG_AUTOHEADER");
10888c2ecf20Sopenharmony_ci	if (!name)
10898c2ecf20Sopenharmony_ci		name = "include/generated/autoconf.h";
10908c2ecf20Sopenharmony_ci	if (make_parent_dir(name))
10918c2ecf20Sopenharmony_ci		return 1;
10928c2ecf20Sopenharmony_ci	if (rename(".tmpconfig.h", name))
10938c2ecf20Sopenharmony_ci		return 1;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	if (make_parent_dir(autoconf_name))
10968c2ecf20Sopenharmony_ci		return 1;
10978c2ecf20Sopenharmony_ci	/*
10988c2ecf20Sopenharmony_ci	 * This must be the last step, kbuild has a dependency on auto.conf
10998c2ecf20Sopenharmony_ci	 * and this marks the successful completion of the previous steps.
11008c2ecf20Sopenharmony_ci	 */
11018c2ecf20Sopenharmony_ci	if (rename(".tmpconfig", autoconf_name))
11028c2ecf20Sopenharmony_ci		return 1;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	return 0;
11058c2ecf20Sopenharmony_ci}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_cistatic int sym_change_count;
11088c2ecf20Sopenharmony_cistatic void (*conf_changed_callback)(void);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_civoid sym_set_change_count(int count)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	int _sym_change_count = sym_change_count;
11138c2ecf20Sopenharmony_ci	sym_change_count = count;
11148c2ecf20Sopenharmony_ci	if (conf_changed_callback &&
11158c2ecf20Sopenharmony_ci	    (bool)_sym_change_count != (bool)count)
11168c2ecf20Sopenharmony_ci		conf_changed_callback();
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_civoid sym_add_change_count(int count)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	sym_set_change_count(count + sym_change_count);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cibool conf_get_changed(void)
11258c2ecf20Sopenharmony_ci{
11268c2ecf20Sopenharmony_ci	return sym_change_count;
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_civoid conf_set_changed_callback(void (*fn)(void))
11308c2ecf20Sopenharmony_ci{
11318c2ecf20Sopenharmony_ci	conf_changed_callback = fn;
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cistatic bool randomize_choice_values(struct symbol *csym)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	struct property *prop;
11378c2ecf20Sopenharmony_ci	struct symbol *sym;
11388c2ecf20Sopenharmony_ci	struct expr *e;
11398c2ecf20Sopenharmony_ci	int cnt, def;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	/*
11428c2ecf20Sopenharmony_ci	 * If choice is mod then we may have more items selected
11438c2ecf20Sopenharmony_ci	 * and if no then no-one.
11448c2ecf20Sopenharmony_ci	 * In both cases stop.
11458c2ecf20Sopenharmony_ci	 */
11468c2ecf20Sopenharmony_ci	if (csym->curr.tri != yes)
11478c2ecf20Sopenharmony_ci		return false;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	prop = sym_get_choice_prop(csym);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/* count entries in choice block */
11528c2ecf20Sopenharmony_ci	cnt = 0;
11538c2ecf20Sopenharmony_ci	expr_list_for_each_sym(prop->expr, e, sym)
11548c2ecf20Sopenharmony_ci		cnt++;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	/*
11578c2ecf20Sopenharmony_ci	 * find a random value and set it to yes,
11588c2ecf20Sopenharmony_ci	 * set the rest to no so we have only one set
11598c2ecf20Sopenharmony_ci	 */
11608c2ecf20Sopenharmony_ci	def = (rand() % cnt);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	cnt = 0;
11638c2ecf20Sopenharmony_ci	expr_list_for_each_sym(prop->expr, e, sym) {
11648c2ecf20Sopenharmony_ci		if (def == cnt++) {
11658c2ecf20Sopenharmony_ci			sym->def[S_DEF_USER].tri = yes;
11668c2ecf20Sopenharmony_ci			csym->def[S_DEF_USER].val = sym;
11678c2ecf20Sopenharmony_ci		}
11688c2ecf20Sopenharmony_ci		else {
11698c2ecf20Sopenharmony_ci			sym->def[S_DEF_USER].tri = no;
11708c2ecf20Sopenharmony_ci		}
11718c2ecf20Sopenharmony_ci		sym->flags |= SYMBOL_DEF_USER;
11728c2ecf20Sopenharmony_ci		/* clear VALID to get value calculated */
11738c2ecf20Sopenharmony_ci		sym->flags &= ~SYMBOL_VALID;
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci	csym->flags |= SYMBOL_DEF_USER;
11768c2ecf20Sopenharmony_ci	/* clear VALID to get value calculated */
11778c2ecf20Sopenharmony_ci	csym->flags &= ~(SYMBOL_VALID);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	return true;
11808c2ecf20Sopenharmony_ci}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_civoid set_all_choice_values(struct symbol *csym)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	struct property *prop;
11858c2ecf20Sopenharmony_ci	struct symbol *sym;
11868c2ecf20Sopenharmony_ci	struct expr *e;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	prop = sym_get_choice_prop(csym);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/*
11918c2ecf20Sopenharmony_ci	 * Set all non-assinged choice values to no
11928c2ecf20Sopenharmony_ci	 */
11938c2ecf20Sopenharmony_ci	expr_list_for_each_sym(prop->expr, e, sym) {
11948c2ecf20Sopenharmony_ci		if (!sym_has_value(sym))
11958c2ecf20Sopenharmony_ci			sym->def[S_DEF_USER].tri = no;
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci	csym->flags |= SYMBOL_DEF_USER;
11988c2ecf20Sopenharmony_ci	/* clear VALID to get value calculated */
11998c2ecf20Sopenharmony_ci	csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cibool conf_set_all_new_symbols(enum conf_def_mode mode)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct symbol *sym, *csym;
12058c2ecf20Sopenharmony_ci	int i, cnt, pby, pty, ptm;	/* pby: probability of bool     = y
12068c2ecf20Sopenharmony_ci					 * pty: probability of tristate = y
12078c2ecf20Sopenharmony_ci					 * ptm: probability of tristate = m
12088c2ecf20Sopenharmony_ci					 */
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
12118c2ecf20Sopenharmony_ci				   * below, otherwise gcc whines about
12128c2ecf20Sopenharmony_ci				   * -Wmaybe-uninitialized */
12138c2ecf20Sopenharmony_ci	if (mode == def_random) {
12148c2ecf20Sopenharmony_ci		int n, p[3];
12158c2ecf20Sopenharmony_ci		char *env = getenv("KCONFIG_PROBABILITY");
12168c2ecf20Sopenharmony_ci		n = 0;
12178c2ecf20Sopenharmony_ci		while( env && *env ) {
12188c2ecf20Sopenharmony_ci			char *endp;
12198c2ecf20Sopenharmony_ci			int tmp = strtol( env, &endp, 10 );
12208c2ecf20Sopenharmony_ci			if( tmp >= 0 && tmp <= 100 ) {
12218c2ecf20Sopenharmony_ci				p[n++] = tmp;
12228c2ecf20Sopenharmony_ci			} else {
12238c2ecf20Sopenharmony_ci				errno = ERANGE;
12248c2ecf20Sopenharmony_ci				perror( "KCONFIG_PROBABILITY" );
12258c2ecf20Sopenharmony_ci				exit( 1 );
12268c2ecf20Sopenharmony_ci			}
12278c2ecf20Sopenharmony_ci			env = (*endp == ':') ? endp+1 : endp;
12288c2ecf20Sopenharmony_ci			if( n >=3 ) {
12298c2ecf20Sopenharmony_ci				break;
12308c2ecf20Sopenharmony_ci			}
12318c2ecf20Sopenharmony_ci		}
12328c2ecf20Sopenharmony_ci		switch( n ) {
12338c2ecf20Sopenharmony_ci		case 1:
12348c2ecf20Sopenharmony_ci			pby = p[0]; ptm = pby/2; pty = pby-ptm;
12358c2ecf20Sopenharmony_ci			break;
12368c2ecf20Sopenharmony_ci		case 2:
12378c2ecf20Sopenharmony_ci			pty = p[0]; ptm = p[1]; pby = pty + ptm;
12388c2ecf20Sopenharmony_ci			break;
12398c2ecf20Sopenharmony_ci		case 3:
12408c2ecf20Sopenharmony_ci			pby = p[0]; pty = p[1]; ptm = p[2];
12418c2ecf20Sopenharmony_ci			break;
12428c2ecf20Sopenharmony_ci		}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci		if( pty+ptm > 100 ) {
12458c2ecf20Sopenharmony_ci			errno = ERANGE;
12468c2ecf20Sopenharmony_ci			perror( "KCONFIG_PROBABILITY" );
12478c2ecf20Sopenharmony_ci			exit( 1 );
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci	bool has_changed = false;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
12538c2ecf20Sopenharmony_ci		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
12548c2ecf20Sopenharmony_ci			continue;
12558c2ecf20Sopenharmony_ci		switch (sym_get_type(sym)) {
12568c2ecf20Sopenharmony_ci		case S_BOOLEAN:
12578c2ecf20Sopenharmony_ci		case S_TRISTATE:
12588c2ecf20Sopenharmony_ci			has_changed = true;
12598c2ecf20Sopenharmony_ci			switch (mode) {
12608c2ecf20Sopenharmony_ci			case def_yes:
12618c2ecf20Sopenharmony_ci				sym->def[S_DEF_USER].tri = yes;
12628c2ecf20Sopenharmony_ci				break;
12638c2ecf20Sopenharmony_ci			case def_mod:
12648c2ecf20Sopenharmony_ci				sym->def[S_DEF_USER].tri = mod;
12658c2ecf20Sopenharmony_ci				break;
12668c2ecf20Sopenharmony_ci			case def_no:
12678c2ecf20Sopenharmony_ci				if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
12688c2ecf20Sopenharmony_ci					sym->def[S_DEF_USER].tri = yes;
12698c2ecf20Sopenharmony_ci				else
12708c2ecf20Sopenharmony_ci					sym->def[S_DEF_USER].tri = no;
12718c2ecf20Sopenharmony_ci				break;
12728c2ecf20Sopenharmony_ci			case def_random:
12738c2ecf20Sopenharmony_ci				sym->def[S_DEF_USER].tri = no;
12748c2ecf20Sopenharmony_ci				cnt = rand() % 100;
12758c2ecf20Sopenharmony_ci				if (sym->type == S_TRISTATE) {
12768c2ecf20Sopenharmony_ci					if (cnt < pty)
12778c2ecf20Sopenharmony_ci						sym->def[S_DEF_USER].tri = yes;
12788c2ecf20Sopenharmony_ci					else if (cnt < (pty+ptm))
12798c2ecf20Sopenharmony_ci						sym->def[S_DEF_USER].tri = mod;
12808c2ecf20Sopenharmony_ci				} else if (cnt < pby)
12818c2ecf20Sopenharmony_ci					sym->def[S_DEF_USER].tri = yes;
12828c2ecf20Sopenharmony_ci				break;
12838c2ecf20Sopenharmony_ci			default:
12848c2ecf20Sopenharmony_ci				continue;
12858c2ecf20Sopenharmony_ci			}
12868c2ecf20Sopenharmony_ci			if (!(sym_is_choice(sym) && mode == def_random))
12878c2ecf20Sopenharmony_ci				sym->flags |= SYMBOL_DEF_USER;
12888c2ecf20Sopenharmony_ci			break;
12898c2ecf20Sopenharmony_ci		default:
12908c2ecf20Sopenharmony_ci			break;
12918c2ecf20Sopenharmony_ci		}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	sym_clear_all_valid();
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	/*
12988c2ecf20Sopenharmony_ci	 * We have different type of choice blocks.
12998c2ecf20Sopenharmony_ci	 * If curr.tri equals to mod then we can select several
13008c2ecf20Sopenharmony_ci	 * choice symbols in one block.
13018c2ecf20Sopenharmony_ci	 * In this case we do nothing.
13028c2ecf20Sopenharmony_ci	 * If curr.tri equals yes then only one symbol can be
13038c2ecf20Sopenharmony_ci	 * selected in a choice block and we set it to yes,
13048c2ecf20Sopenharmony_ci	 * and the rest to no.
13058c2ecf20Sopenharmony_ci	 */
13068c2ecf20Sopenharmony_ci	if (mode != def_random) {
13078c2ecf20Sopenharmony_ci		for_all_symbols(i, csym) {
13088c2ecf20Sopenharmony_ci			if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
13098c2ecf20Sopenharmony_ci			    sym_is_choice_value(csym))
13108c2ecf20Sopenharmony_ci				csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
13118c2ecf20Sopenharmony_ci		}
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	for_all_symbols(i, csym) {
13158c2ecf20Sopenharmony_ci		if (sym_has_value(csym) || !sym_is_choice(csym))
13168c2ecf20Sopenharmony_ci			continue;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		sym_calc_value(csym);
13198c2ecf20Sopenharmony_ci		if (mode == def_random)
13208c2ecf20Sopenharmony_ci			has_changed |= randomize_choice_values(csym);
13218c2ecf20Sopenharmony_ci		else {
13228c2ecf20Sopenharmony_ci			set_all_choice_values(csym);
13238c2ecf20Sopenharmony_ci			has_changed = true;
13248c2ecf20Sopenharmony_ci		}
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	return has_changed;
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_civoid conf_rewrite_mod_or_yes(enum conf_def_mode mode)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct symbol *sym;
13338c2ecf20Sopenharmony_ci	int i;
13348c2ecf20Sopenharmony_ci	tristate old_val = (mode == def_y2m) ? yes : mod;
13358c2ecf20Sopenharmony_ci	tristate new_val = (mode == def_y2m) ? mod : yes;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	for_all_symbols(i, sym) {
13388c2ecf20Sopenharmony_ci		if (sym_get_type(sym) == S_TRISTATE &&
13398c2ecf20Sopenharmony_ci		    sym->def[S_DEF_USER].tri == old_val)
13408c2ecf20Sopenharmony_ci			sym->def[S_DEF_USER].tri = new_val;
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci	sym_clear_all_valid();
13438c2ecf20Sopenharmony_ci}
1344