From e8440b5c2722b2740b7fd444edcd7cbd531ccddb Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 6 Apr 2014 14:46:57 +0200 Subject: use lowercase directory name --- toolchain/uclibc/Makefile | 129 + toolchain/uclibc/Makefile.inc | 10 + toolchain/uclibc/patches/uclibc-git-20140313.patch | 116105 ++++++++++++++++++ toolchain/uclibc/patches/xxx-origin.patch | 177 + toolchain/uclibc/patches/xxx-sparc-wait4.patch | 12 + 5 files changed, 116433 insertions(+) create mode 100644 toolchain/uclibc/Makefile create mode 100644 toolchain/uclibc/Makefile.inc create mode 100644 toolchain/uclibc/patches/uclibc-git-20140313.patch create mode 100644 toolchain/uclibc/patches/xxx-origin.patch create mode 100644 toolchain/uclibc/patches/xxx-sparc-wait4.patch (limited to 'toolchain/uclibc') diff --git a/toolchain/uclibc/Makefile b/toolchain/uclibc/Makefile new file mode 100644 index 000000000..94a81391d --- /dev/null +++ b/toolchain/uclibc/Makefile @@ -0,0 +1,129 @@ +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +_IN_CVTC= 1 + +include $(TOPDIR)/rules.mk +include ../rules.mk +include Makefile.inc +include ${TOPDIR}/mk/buildhlp.mk + +TARGET_CFLAGS:=$(filter-out -flto,$(TARGET_CFLAGS)) + +ifeq (${ADK_MAKE_PARALLEL},y) +UCLIBC_MAKEOPTS+= -j${ADK_MAKE_JOBS} +endif + +$(WRKBUILD)/.headers: + $(SED) 's,^CROSS_COMPILE=.*,CROSS_COMPILE=$(TARGET_CROSS),g' $(WRKBUILD)/Rules.mak + sed -e 's^KERNEL_HEADERS.*$$KERNEL_HEADERS=\"${STAGING_TARGET_DIR}/usr/include\"' \ + $(TOPDIR)/target/$(ADK_TARGET_ARCH)/uclibc.config >${WRKBUILD}/.config +ifeq ($(ADK_TARGET_ENDIAN),little) + $(SED) 's/.*\(ARCH_LITTLE_ENDIAN\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_WANTS_LITTLE_ENDIAN\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_BIG_ENDIAN\).*/# \1 is not set/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_WANTS_BIG_ENDIAN\).*/# \1 is not set/' ${WRKBUILD}/.config +else + $(SED) 's/.*\(ARCH_BIG_ENDIAN\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_WANTS_BIG_ENDIAN\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_LITTLE_ENDIAN\).*/# \1 is not set/' ${WRKBUILD}/.config + $(SED) 's/.*\(ARCH_WANTS_LITTLE_ENDIAN\).*/# \1 is not set/' ${WRKBUILD}/.config +endif +ifeq ($(ADK_LINUX_64),y) + $(SED) 's/.*\(CONFIG_MIPS_ISA_MIPS64\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_ISA_MIPS32\).*/# \1 is not set/' ${WRKBUILD}/.config +else + $(SED) 's/.*\(CONFIG_MIPS_ISA_MIPS32\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_ISA_MIPS64\).*/# \1 is not set/' ${WRKBUILD}/.config +endif +ifeq ($(ADK_n64),y) + $(SED) 's/.*\(CONFIG_MIPS_N64_ABI\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_O32_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_N32_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config +endif +ifeq ($(ADK_n32),y) + $(SED) 's/.*\(CONFIG_MIPS_N32_ABI\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_O32_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_N64_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config +endif +ifeq ($(ADK_o32),y) + $(SED) 's/.*\(CONFIG_MIPS_O32_ABI\).*/\1=y/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_N32_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config + $(SED) 's/.*\(CONFIG_MIPS_N64_ABI\).*/# \1 is not set/' ${WRKBUILD}/.config +endif +ifneq ($(ADK_PACKAGE_GDB),) + $(SED) "s/.*\(PTHREADS_DEBUG_SUPPORT\).*/\1=y/" ${WRKBUILD}/.config +endif +ifeq ($(ADK_LINUX_ARM_WITH_THUMB),y) + $(SED) 's/.*\(COMPILE_IN_THUMB_MODE\).*/\1=y/' ${WRKBUILD}/.config +endif +ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y) + $(SED) 's,.*UCLIBC_HAS_SSP,UCLIBC_HAS_SSP=y,' ${WRKBUILD}/.config + echo "UCLIBC_HAS_SSP_COMPAT=n" >> ${WRKBUILD}/.config + echo "SSP_QUICK_CANARY=n" >> ${WRKBUILD}/.config + echo "UCLIBC_BUILD_SSP=y" >> ${WRKBUILD}/.config +endif + echo N|$(MAKE) ${UCLIBC_MAKEOPTS} -C $(WRKBUILD) \ + PREFIX=$(STAGING_TARGET_DIR) \ + DEVEL_PREFIX=/usr/ \ + RUNTIME_PREFIX=$(STAGING_TARGET_DIR) \ + HOSTCC="$(CC_FOR_BUILD)" \ + CPU_CFLAGS="$(TARGET_CFLAGS)" \ + oldconfig + $(MAKE) ${UCLIBC_MAKEOPTS} -C $(WRKBUILD) \ + PREFIX=$(STAGING_TARGET_DIR) \ + DEVEL_PREFIX=/usr/ \ + RUNTIME_PREFIX=$(STAGING_TARGET_DIR) \ + HOSTCC="$(CC_FOR_BUILD)" \ + CPU_CFLAGS="$(TARGET_CFLAGS)" \ + install_headers + touch $(WRKBUILD)/.configured + touch $@ + +$(WRKBUILD)/.compiled: + $(MAKE) ${UCLIBC_MAKEOPTS} -C $(WRKBUILD) \ + PREFIX= \ + DEVEL_PREFIX=/ \ + RUNTIME_PREFIX=/ \ + HOSTCC="$(CC_FOR_BUILD)" \ + CPU_CFLAGS="$(TARGET_CFLAGS)" \ + all + touch $@ + +$(WRKBUILD)/.install_headers: $(WRKBUILD)/.compiled + $(MAKE) -C $(WRKBUILD) \ + PREFIX=$(STAGING_TARGET_DIR) \ + DEVEL_PREFIX=/usr/ \ + DEVEL_PREFIX_LIB=/ \ + RUNTIME_PREFIX=/ \ + CPU_CFLAGS="$(TARGET_CFLAGS)" \ + install_dev + touch $@ + +$(WRKBUILD)/.installed: $(WRKBUILD)/.install_headers + touch $@ + +$(WRKBUILD)/.fixup: + # DOSTRIP kills x86 target (ld.so can not map libc.so.0), always use DODEBUG + # DODEBUG compile failure linking with libgcc_eh.a on arm hf +ifneq ($(ADK_LINUX_ARM),y) + $(SED) 's,DOSTRIP,DODEBUG,' ${WRKBUILD}/.config +endif + $(MAKE) -C $(WRKBUILD) \ + PREFIX=$(STAGING_TARGET_DIR) \ + DEVEL_PREFIX=/usr/ \ + DEVEL_PREFIX_LIB=/ \ + RUNTIME_PREFIX=/ \ + CPU_CFLAGS="$(TARGET_CFLAGS)" \ + all install_runtime + # cleanup toolchain + -find $(STAGING_TARGET_DIR) $(STAGING_HOST_DIR) -name \*.la -delete +ifeq ($(ADK_TOOLCHAIN),y) + # strip target libs and host tools for toolchain builds + PATH="$(TARGET_PATH)" debug='0' prefix='${TARGET_CROSS}' ${BASH} ${SCRIPT_DIR}/rstrip.sh \ + $(STAGING_TARGET_DIR) $(TOOLCHAIN_DIR)/usr/lib/gcc/$(GNU_TARGET_NAME) + debug='0' prefix=' ' ${BASH} ${SCRIPT_DIR}/rstrip.sh $(TOOLCHAIN_DIR)/usr/bin +endif + touch $@ + +include ${TOPDIR}/mk/toolchain.mk diff --git a/toolchain/uclibc/Makefile.inc b/toolchain/uclibc/Makefile.inc new file mode 100644 index 000000000..eff931e2b --- /dev/null +++ b/toolchain/uclibc/Makefile.inc @@ -0,0 +1,10 @@ +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +PKG_NAME:= uClibc +PKG_VERSION:= 0.9.33.2 +GIT_VERSION:= 0.9.34-git +PKG_RELEASE:= 1 +PKG_MD5SUM:= 73e6fe215648d02246f4d195b25fb17e +PKG_SITES:= http://uclibc.org/downloads/ +DISTFILES:= $(PKG_NAME)-$(PKG_VERSION).tar.xz diff --git a/toolchain/uclibc/patches/uclibc-git-20140313.patch b/toolchain/uclibc/patches/uclibc-git-20140313.patch new file mode 100644 index 000000000..561c08007 --- /dev/null +++ b/toolchain/uclibc/patches/uclibc-git-20140313.patch @@ -0,0 +1,116105 @@ +diff -Nur uClibc-0.9.33.2/docs/man/arc4random.3 uClibc-git/docs/man/arc4random.3 +--- uClibc-0.9.33.2/docs/man/arc4random.3 1970-01-01 01:00:00.000000000 +0100 ++++ uClibc-git/docs/man/arc4random.3 2014-02-03 12:32:56.000000000 +0100 +@@ -0,0 +1,110 @@ ++.\" $OpenBSD: arc4random.3,v 1.19 2005/07/17 08:50:55 jaredy Exp $ ++.\" ++.\" Copyright 1997 Niels Provos ++.\" All rights reserved. ++.\" ++.\" Redistribution and use in source and binary forms, with or without ++.\" modification, are permitted provided that the following conditions ++.\" are met: ++.\" 1. Redistributions of source code must retain the above copyright ++.\" notice, this list of conditions and the following disclaimer. ++.\" 2. Redistributions in binary form must reproduce the above copyright ++.\" notice, this list of conditions and the following disclaimer in the ++.\" documentation and/or other materials provided with the distribution. ++.\" 3. All advertising materials mentioning features or use of this software ++.\" must display the following acknowledgement: ++.\" This product includes software developed by Niels Provos. ++.\" 4. The name of the author may not be used to endorse or promote products ++.\" derived from this software without specific prior written permission. ++.\" ++.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++.\" ++.\" Manual page, using -mandoc macros ++.\" ++.Dd April 15, 1997 ++.Dt ARC4RANDOM 3 ++.Os ++.Sh NAME ++.Nm arc4random , ++.Nm arc4random_stir , ++.Nm arc4random_addrandom ++.Nd arc4 random number generator ++.Sh SYNOPSIS ++.Fd #include ++.Ft uint32_t ++.Fn arc4random "void" ++.Ft void ++.Fn arc4random_stir "void" ++.Ft void ++.Fn arc4random_addrandom "u_char *dat" "int datlen" ++.Sh DESCRIPTION ++The ++.Fn arc4random ++function provides a high quality 32-bit pseudo-random ++number very quickly. ++.Fn arc4random ++seeds itself on a regular basis from the kernel strong random number ++subsystem described in ++.Xr random 4 . ++On each call, an ARC4 generator is used to generate a new result. ++The ++.Fn arc4random ++function uses the ARC4 cipher key stream generator, ++which uses 8*8 8-bit S-Boxes. ++The S-Boxes can be in about (2**1700) states. ++.Pp ++.Fn arc4random ++fits into a middle ground not covered by other subsystems such as ++the strong, slow, and resource expensive random ++devices described in ++.Xr random 4 ++versus the fast but poor quality interfaces described in ++.Xr rand 3 , ++.Xr random 3 , ++and ++.Xr drand48 3 . ++.Pp ++The ++.Fn arc4random_stir ++function reads data from a pseudo-random device, usually ++.Pa /dev/urandom, ++and uses it to permute the S-Boxes via ++.Fn arc4random_addrandom . ++.Pp ++There is no need to call ++.Fn arc4random_stir ++before using ++.Fn arc4random , ++since ++.Fn arc4random ++automatically initializes itself. ++.Sh SEE ALSO ++.Xr rand 3 , ++.Xr rand48 3 , ++.Xr random 3 ++.Sh HISTORY ++An algorithm called ++.Pa RC4 ++was designed by RSA Data Security, Inc. ++It was considered a trade secret. ++Because it was a trade secret, it obviously could not be patented. ++A clone of this was posted anonymously to USENET and confirmed to ++be equivalent by several sources who had access to the original cipher. ++Because of the trade secret situation, RSA Data Security, Inc. can do ++nothing about the release of the ARC4 algorithm. ++Since ++.Pa RC4 ++used to be a trade secret, the cipher is now referred to as ++.Pa ARC4 . ++.Pp ++These functions first appeared in ++.Ox 2.1 . +diff -Nur uClibc-0.9.33.2/docs/PORTING uClibc-git/docs/PORTING +--- uClibc-0.9.33.2/docs/PORTING 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/docs/PORTING 2014-02-03 12:32:56.000000000 +0100 +@@ -130,9 +130,6 @@ + ==================== + === Misc Cruft === + ==================== +-- utils/readelf.c - not really needed generally speaking, but might as well +- add your arch to the giant EM_* list (describe_elf_hdr) +- + - MAINTAINERS - presumably you're going to submit this code back to mainline + and since you're the only one who cares about this arch (right now), you + should add yourself to the toplevel MAINTAINERS file. do it. +diff -Nur uClibc-0.9.33.2/extra/config/check.sh uClibc-git/extra/config/check.sh +--- uClibc-0.9.33.2/extra/config/check.sh 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/extra/config/check.sh 2014-02-03 12:32:56.000000000 +0100 +@@ -1,6 +1,6 @@ + #!/bin/sh + # Needed for systems without gettext +-$* -xc -o /dev/null - > /dev/null 2>&1 << EOF ++$* -x c -o /dev/null - > /dev/null 2>&1 << EOF + #include + int main() + { +diff -Nur uClibc-0.9.33.2/extra/config/conf.c uClibc-git/extra/config/conf.c +--- uClibc-0.9.33.2/extra/config/conf.c 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/extra/config/conf.c 2014-02-03 12:32:56.000000000 +0100 +@@ -10,42 +10,48 @@ + #include + #include + #include ++#include + #include + #include ++#include + +-#define LKC_DIRECT_LINK + #include "lkc.h" + + static void conf(struct menu *menu); + static void check_conf(struct menu *menu); ++static void xfgets(char *str, int size, FILE *in); + +-enum { +- ask_all, +- ask_new, +- ask_silent, +- set_default, +- set_yes, +- set_mod, +- set_no, +- set_random +-} input_mode = ask_all; +-char *defconfig_file; ++enum input_mode { ++ oldaskconfig, ++ silentoldconfig, ++ oldconfig, ++ allnoconfig, ++ allyesconfig, ++ allmodconfig, ++ alldefconfig, ++ randconfig, ++ defconfig, ++ savedefconfig, ++ listnewconfig, ++ olddefconfig, ++} input_mode = oldaskconfig; + + static int indent = 1; ++static int tty_stdio; + static int valid_stdin = 1; + static int sync_kconfig; + static int conf_cnt; + static char line[128]; + static struct menu *rootEntry; + +-static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n"); +- +-static const char *get_help(struct menu *menu) ++static void print_help(struct menu *menu) + { +- if (menu_has_help(menu)) +- return _(menu_get_help(menu)); +- else +- return nohelp_text; ++ struct gstr help = str_new(); ++ ++ menu_get_ext_help(menu, &help); ++ ++ printf("\n%s\n", str_get(&help)); ++ str_free(&help); + } + + static void strip(char *str) +@@ -93,16 +99,19 @@ + } + + switch (input_mode) { +- case ask_new: +- case ask_silent: ++ case oldconfig: ++ case silentoldconfig: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); +- case ask_all: ++ /* fall through */ ++ case oldaskconfig: + fflush(stdout); +- fgets(line, 128, stdin); ++ xfgets(line, 128, stdin); ++ if (!tty_stdio) ++ printf("\n"); + return 1; + default: + break; +@@ -121,7 +130,7 @@ + return 1; + } + +-int conf_string(struct menu *menu) ++static int conf_string(struct menu *menu) + { + struct symbol *sym = menu->sym; + const char *def; +@@ -140,10 +149,11 @@ + case '?': + /* print help */ + if (line[1] == '\n') { +- printf("\n%s\n", get_help(menu)); ++ print_help(menu); + def = NULL; + break; + } ++ /* fall through */ + default: + line[strlen(line)-1] = 0; + def = line; +@@ -156,14 +166,12 @@ + static int conf_sym(struct menu *menu) + { + struct symbol *sym = menu->sym; +- int type; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); +- type = sym_get_type(sym); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { +@@ -220,7 +228,7 @@ + if (sym_set_tristate_value(sym, newval)) + return 0; + help: +- printf("\n%s\n", get_help(menu)); ++ print_help(menu); + } + } + +@@ -228,11 +236,9 @@ + { + struct symbol *sym, *def_sym; + struct menu *child; +- int type; + bool is_new; + + sym = menu->sym; +- type = sym_get_type(sym); + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); +@@ -294,20 +300,21 @@ + printf("?"); + printf("]: "); + switch (input_mode) { +- case ask_new: +- case ask_silent: ++ case oldconfig: ++ case silentoldconfig: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); +- case ask_all: ++ /* fall through */ ++ case oldaskconfig: + fflush(stdout); +- fgets(line, 128, stdin); ++ xfgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { +- printf("\n%s\n", get_help(menu)); ++ print_help(menu); + continue; + } + if (!line[0]) +@@ -330,8 +337,8 @@ + } + if (!child) + continue; +- if (line[strlen(line) - 1] == '?') { +- printf("\n%s\n", get_help(child)); ++ if (line[0] && line[strlen(line) - 1] == '?') { ++ print_help(child); + continue; + } + sym_set_choice_value(sym, child->sym); +@@ -360,10 +367,14 @@ + + switch (prop->type) { + case P_MENU: +- if (input_mode == ask_silent && rootEntry != menu) { ++ if ((input_mode == silentoldconfig || ++ input_mode == listnewconfig || ++ input_mode == olddefconfig) && ++ rootEntry != menu) { + check_conf(menu); + return; + } ++ /* fall through */ + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) +@@ -418,10 +429,16 @@ + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { +- if (!conf_cnt++) +- printf(_("*\n* Restart config...\n*\n")); +- rootEntry = menu_get_parent_menu(menu); +- conf(rootEntry); ++ if (input_mode == listnewconfig) { ++ if (sym->name && !sym_is_choice_value(sym)) { ++ printf("%s%s\n", CONFIG_, sym->name); ++ } ++ } else if (input_mode != olddefconfig) { ++ if (!conf_cnt++) ++ printf(_("*\n* Restart config...\n*\n")); ++ rootEntry = menu_get_parent_menu(menu); ++ conf(rootEntry); ++ } + } + } + +@@ -429,90 +446,170 @@ + check_conf(child); + } + ++#if 00 // || !defined __UCLIBC__ || \ ++ (defined UCLIBC_HAS_GETOPT_LONG || defined UCLIBC_HAS_GNU_GETOPT) ++static struct option long_opts[] = { ++ {"oldaskconfig", no_argument, NULL, oldaskconfig}, ++ {"oldconfig", no_argument, NULL, oldconfig}, ++ {"silentoldconfig", no_argument, NULL, silentoldconfig}, ++ {"defconfig", optional_argument, NULL, defconfig}, ++ {"savedefconfig", required_argument, NULL, savedefconfig}, ++ {"allnoconfig", no_argument, NULL, allnoconfig}, ++ {"allyesconfig", no_argument, NULL, allyesconfig}, ++ {"allmodconfig", no_argument, NULL, allmodconfig}, ++ {"alldefconfig", no_argument, NULL, alldefconfig}, ++ {"randconfig", no_argument, NULL, randconfig}, ++ {"listnewconfig", no_argument, NULL, listnewconfig}, ++ {"olddefconfig", no_argument, NULL, olddefconfig}, ++ /* ++ * oldnoconfig is an alias of olddefconfig, because people already ++ * are dependent on its behavior(sets new symbols to their default ++ * value but not 'n') with the counter-intuitive name. ++ */ ++ {"oldnoconfig", no_argument, NULL, olddefconfig}, ++ {NULL, 0, NULL, 0} ++}; ++ ++static void conf_usage(const char *progname) ++{ ++ ++ printf("Usage: %s [option] \n", progname); ++ printf("[option] is _one_ of the following:\n"); ++ printf(" --listnewconfig List new options\n"); ++ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); ++ printf(" --oldconfig Update a configuration using a provided .config as base\n"); ++ printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); ++ printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); ++ printf(" --oldnoconfig An alias of olddefconfig\n"); ++ printf(" --defconfig New config with default defined in \n"); ++ printf(" --savedefconfig Save the minimal current configuration to \n"); ++ printf(" --allnoconfig New config where all options are answered with no\n"); ++ printf(" --allyesconfig New config where all options are answered with yes\n"); ++ printf(" --allmodconfig New config where all options are answered with mod\n"); ++ printf(" --alldefconfig New config with all symbols set to default\n"); ++ printf(" --randconfig New config with random answer to all options\n"); ++} ++#else ++static void conf_usage(const char *progname) ++{ ++ ++ printf("Usage: %s [option] \n", progname); ++ printf("[option] is _one_ of the following:\n"); ++ printf(" -a, --oldaskconfig Start a new configuration using a line-oriented program\n"); ++ printf(" -s, --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); ++ printf(" -o, --oldconfig Update a configuration using a provided .config as base\n"); ++ printf(" -n, --allnoconfig New config where all options are answered with no\n"); ++ printf(" -y, --allyesconfig New config where all options are answered with yes\n"); ++ printf(" -m, --allmodconfig New config where all options are answered with mod\n"); ++ printf(" -A, --alldefconfig New config with all symbols set to default\n"); ++ printf(" -r, --randconfig New config with random answer to all options\n"); ++ printf(" -D, --defconfig New config with default defined in \n"); ++ printf(" -S, --savedefconfig Save the minimal current configuration to \n"); ++ printf(" -l, --listnewconfig List new options\n"); ++ printf(" -d, --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); ++ printf(" --oldnoconfig An alias of olddefconfig\n"); ++ ++} ++#endif ++ + int main(int ac, char **av) + { ++ const char *progname = av[0]; + int opt; +- const char *name; +- const char *configname = conf_get_configname(); ++ const char *name, *defconfig_file = NULL /* gcc uninit */; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + +- while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) { ++ tty_stdio = isatty(0) && isatty(1) && isatty(2); ++ ++#if 00// !defined __UCLIBC__ || \ ++ (defined UCLIBC_HAS_GETOPT_LONG || defined UCLIBC_HAS_GNU_GETOPT) ++ while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) ++#else ++ char *gch = "asonymArDSld"; ++ while ((opt = getopt(ac, av, "asonymArD:S:ldh")) != -1) ++#endif ++ { ++ char *x = memchr(gch, opt, strlen(gch)); ++ if (x == NULL) ++ opt = '?'; ++ else ++ opt = x - gch; ++ input_mode = (enum input_mode)opt; + switch (opt) { +- case 'o': +- input_mode = ask_silent; +- break; +- case 's': +- input_mode = ask_silent; ++ case silentoldconfig: + sync_kconfig = 1; + break; +- case 'd': +- input_mode = set_default; +- break; +- case 'D': +- input_mode = set_default; ++ case defconfig: ++ case savedefconfig: + defconfig_file = optarg; + break; +- case 'n': +- input_mode = set_no; +- break; +- case 'm': +- input_mode = set_mod; +- break; +- case 'y': +- input_mode = set_yes; +- break; +- case 'r': ++ case randconfig: + { + struct timeval now; + unsigned int seed; ++ char *seed_env; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); +- + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); +- srand(seed); + +- input_mode = set_random; ++ seed_env = getenv("KCONFIG_SEED"); ++ if( seed_env && *seed_env ) { ++ char *endp; ++ int tmp = (int)strtol(seed_env, &endp, 0); ++ if (*endp == '\0') { ++ seed = tmp; ++ } ++ } ++ fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); ++ srand(seed); + break; + } +- case 'h': +- printf(_("See README for usage info\n")); +- exit(0); ++ case oldaskconfig: ++ case oldconfig: ++ case allnoconfig: ++ case allyesconfig: ++ case allmodconfig: ++ case alldefconfig: ++ case listnewconfig: ++ case olddefconfig: + break; +- default: +- fprintf(stderr, _("See README for usage info\n")); ++ case '?': ++ conf_usage(progname); + exit(1); ++ break; + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); ++ conf_usage(progname); + exit(1); + } + name = av[optind]; + conf_parse(name); + //zconfdump(stdout); + if (sync_kconfig) { +- if (stat(configname, &tmpstat)) { ++ name = conf_get_configname(); ++ if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" +- "*** You have not yet configured!\n" +- "*** (missing .config file)\n" ++ "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" +- "***\n")); ++ "***\n"), name); + exit(1); + } + } + + switch (input_mode) { +- case set_default: ++ case defconfig: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { +@@ -522,31 +619,46 @@ + exit(1); + } + break; +- case ask_silent: +- case ask_all: +- case ask_new: ++ case savedefconfig: ++ case silentoldconfig: ++ case oldaskconfig: ++ case oldconfig: ++ case listnewconfig: ++ case olddefconfig: + conf_read(NULL); + break; +- case set_no: +- case set_mod: +- case set_yes: +- case set_random: ++ case allnoconfig: ++ case allyesconfig: ++ case allmodconfig: ++ case alldefconfig: ++ case randconfig: + name = getenv("KCONFIG_ALLCONFIG"); +- if (name && !stat(name, &tmpstat)) { +- conf_read_simple(name, S_DEF_USER); ++ if (!name) ++ break; ++ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { ++ if (conf_read_simple(name, S_DEF_USER)) { ++ fprintf(stderr, ++ _("*** Can't read seed configuration \"%s\"!\n"), ++ name); ++ exit(1); ++ } + break; + } + switch (input_mode) { +- case set_no: name = "allno.config"; break; +- case set_mod: name = "allmod.config"; break; +- case set_yes: name = "allyes.config"; break; +- case set_random: name = "allrandom.config"; break; ++ case allnoconfig: name = "allno.config"; break; ++ case allyesconfig: name = "allyes.config"; break; ++ case allmodconfig: name = "allmod.config"; break; ++ case alldefconfig: name = "alldef.config"; break; ++ case randconfig: name = "allrandom.config"; break; + default: break; + } +- if (!stat(name, &tmpstat)) +- conf_read_simple(name, S_DEF_USER); +- else if (!stat("all.config", &tmpstat)) +- conf_read_simple("all.config", S_DEF_USER); ++ if (conf_read_simple(name, S_DEF_USER) && ++ conf_read_simple("all.config", S_DEF_USER)) { ++ fprintf(stderr, ++ _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), ++ name); ++ exit(1); ++ } + break; + default: + break; +@@ -557,41 +669,51 @@ + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, +- _("\n*** configuration requires explicit update.\n\n")); ++ _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } +- valid_stdin = isatty(0) && isatty(1) && isatty(2); ++ valid_stdin = tty_stdio; + } + + switch (input_mode) { +- case set_no: ++ case allnoconfig: + conf_set_all_new_symbols(def_no); + break; +- case set_yes: ++ case allyesconfig: + conf_set_all_new_symbols(def_yes); + break; +- case set_mod: ++ case allmodconfig: + conf_set_all_new_symbols(def_mod); + break; +- case set_random: +- conf_set_all_new_symbols(def_random); ++ case alldefconfig: ++ conf_set_all_new_symbols(def_default); ++ break; ++ case randconfig: ++ /* Really nothing to do in this loop */ ++ while (conf_set_all_new_symbols(def_random)) ; + break; +- case set_default: ++ case defconfig: + conf_set_all_new_symbols(def_default); + break; +- case ask_new: +- case ask_all: ++ case savedefconfig: ++ break; ++ case oldaskconfig: + rootEntry = &rootmenu; + conf(&rootmenu); +- input_mode = ask_silent; ++ input_mode = silentoldconfig; + /* fall through */ +- case ask_silent: ++ case oldconfig: ++ case listnewconfig: ++ case olddefconfig: ++ case silentoldconfig: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); +- } while (conf_cnt); ++ } while (conf_cnt && ++ (input_mode != listnewconfig && ++ input_mode != olddefconfig)); + break; + } + +@@ -607,7 +729,13 @@ + fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + return 1; + } +- } else { ++ } else if (input_mode == savedefconfig) { ++ if (conf_write_defconfig(defconfig_file)) { ++ fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), ++ defconfig_file); ++ return 1; ++ } ++ } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); +@@ -615,3 +743,12 @@ + } + return 0; + } ++ ++/* ++ * Helper function to facilitate fgets() by Jean Sacren. ++ */ ++void xfgets(char *str, int size, FILE *in) ++{ ++ if (fgets(str, size, in) == NULL) ++ fprintf(stderr, "\nError in reading or end of file.\n"); ++} +diff -Nur uClibc-0.9.33.2/extra/config/confdata.c uClibc-git/extra/config/confdata.c +--- uClibc-0.9.33.2/extra/config/confdata.c 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/extra/config/confdata.c 2014-02-03 12:32:56.000000000 +0100 +@@ -5,24 +5,27 @@ + + #include + #include ++#include + #include ++#include + #include + #include + #include + #include + #include +-#include + +-#define LKC_DIRECT_LINK + #include "lkc.h" + + static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + ++static void conf_message(const char *fmt, ...) ++ __attribute__ ((format (printf, 1, 2))); ++ + static const char *conf_filename; + static int conf_lineno, conf_warnings, conf_unsaved; + +-const char conf_defname[] = "extra/Configs/defconfigs/$ARCH"; ++const char conf_defname[] = "arch/$ARCH/defconfig"; + + static void conf_warning(const char *fmt, ...) + { +@@ -35,6 +38,29 @@ + conf_warnings++; + } + ++static void conf_default_message_callback(const char *fmt, va_list ap) ++{ ++ printf("#\n# "); ++ vprintf(fmt, ap); ++ printf("\n#\n"); ++} ++ ++static void (*conf_message_callback) (const char *fmt, va_list ap) = ++ conf_default_message_callback; ++void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) ++{ ++ conf_message_callback = fn; ++} ++ ++static void conf_message(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ if (conf_message_callback) ++ conf_message_callback(fmt, ap); ++} ++ + const char *conf_get_configname(void) + { + char *name = getenv("KCONFIG_CONFIG"); +@@ -42,6 +68,13 @@ + return name ? name : ".config"; + } + ++const char *conf_get_autoconfig_name(void) ++{ ++ char *name = getenv("KCONFIG_AUTOCONFIG"); ++ ++ return name ? name : "include/config/auto.conf"; ++} ++ + static char *conf_expand_value(const char *in) + { + struct symbol *sym; +@@ -95,6 +128,7 @@ + sym->flags |= def_flags; + break; + } ++ /* fall through */ + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; +@@ -107,7 +141,7 @@ + break; + } + conf_warning("symbol value '%s' invalid for %s", p, sym->name); +- break; ++ return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) +@@ -115,6 +149,7 @@ + sym->type = S_STRING; + goto done; + } ++ /* fall through */ + case S_STRING: + if (*p++ != '"') + break; +@@ -129,6 +164,7 @@ + conf_warning("invalid string found"); + return 1; + } ++ /* fall through */ + case S_INT: + case S_HEX: + done: +@@ -146,10 +182,66 @@ + return 0; + } + ++#define LINE_GROWTH 16 ++static int add_byte(int c, char **lineptr, size_t slen, size_t *n) ++{ ++ char *nline; ++ size_t new_size = slen + 1; ++ if (new_size > *n) { ++ new_size += LINE_GROWTH - 1; ++ new_size *= 2; ++ nline = realloc(*lineptr, new_size); ++ if (!nline) ++ return -1; ++ ++ *lineptr = nline; ++ *n = new_size; ++ } ++ ++ (*lineptr)[slen] = c; ++ ++ return 0; ++} ++ ++static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) ++{ ++ char *line = *lineptr; ++ size_t slen = 0; ++ ++ for (;;) { ++ int c = getc(stream); ++ ++ switch (c) { ++ case '\n': ++ if (add_byte(c, &line, slen, n) < 0) ++ goto e_out; ++ slen++; ++ /* fall through */ ++ case EOF: ++ if (add_byte('\0', &line, slen, n) < 0) ++ goto e_out; ++ *lineptr = line; ++ if (slen == 0) ++ return -1; ++ return slen; ++ default: ++ if (add_byte(c, &line, slen, n) < 0) ++ goto e_out; ++ slen++; ++ } ++ } ++ ++e_out: ++ line[slen-1] = '\0'; ++ *lineptr = line; ++ return -1; ++} ++ + int conf_read_simple(const char *name, int def) + { + FILE *in = NULL; +- char line[1024]; ++ char *line = NULL; ++ size_t line_asize = 0; + char *p, *p2; + struct symbol *sym; + int i, def_flags; +@@ -164,8 +256,11 @@ + if (in) + goto load; + sym_add_change_count(1); +- if (!sym_defconfig_list) ++ if (!sym_defconfig_list) { ++ if (modules_sym) ++ sym_calc_value(modules_sym); + return 1; ++ } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || +@@ -174,9 +269,8 @@ + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { +- printf(_("#\n" +- "# using defaults found in %s\n" +- "#\n"), name); ++ conf_message(_("using defaults found in %s"), ++ name); + goto load; + } + } +@@ -202,33 +296,33 @@ + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); ++ /* fall through */ + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + +- while (fgets(line, sizeof(line), in)) { ++ while (compat_getline(&line, &line_asize, in) != -1) { + conf_lineno++; + sym = NULL; +- switch (line[0]) { +- case '#': +- if (line[1] != ' ') ++ if (line[0] == '#') { ++ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; +- p = strchr(line + 2, ' '); ++ p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { +- sym = sym_find(line + 2); ++ sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); +- break; ++ goto setsym; + } + } else { +- sym = sym_lookup(line + 2, 0); ++ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } +@@ -244,13 +338,10 @@ + default: + ; + } +- break; +- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': +- p = strchr(line, '='); +- if (!p) { +- conf_warning("unexpected data '%s'", line); ++ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { ++ p = strchr(line + strlen(CONFIG_), '='); ++ if (!p) + continue; +- } + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { +@@ -259,13 +350,13 @@ + *p2 = 0; + } + if (def == S_DEF_USER) { +- sym = sym_find(line); ++ sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); +- break; ++ goto setsym; + } + } else { +- sym = sym_lookup(line, 0); ++ sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } +@@ -274,14 +365,12 @@ + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; +- break; +- case '\r': +- case '\n': +- break; +- default: +- conf_warning("unexpected data"); ++ } else { ++ if (line[0] != '\r' && line[0] != '\n') ++ conf_warning("unexpected data"); + continue; + } ++setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { +@@ -302,6 +391,7 @@ + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } ++ free(line); + fclose(in); + + if (modules_sym) +@@ -311,10 +401,8 @@ + + int conf_read(const char *name) + { +- struct symbol *sym, *choice_sym; +- struct property *prop; +- struct expr *e; +- int i, flags; ++ struct symbol *sym; ++ int i; + + sym_set_change_count(0); + +@@ -324,7 +412,7 @@ + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) +- goto sym_ok; ++ continue; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { +@@ -333,29 +421,18 @@ + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) +- goto sym_ok; ++ continue; ++ /* fall through */ + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) +- goto sym_ok; ++ continue; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ +- goto sym_ok; ++ continue; + conf_unsaved++; + /* maybe print value in verbose mode... */ +- sym_ok: +- if (!sym_is_choice(sym)) +- continue; +- /* The choice symbol only has a set value (and thus is not new) +- * if all its visible childs have values. +- */ +- prop = sym_get_choice_prop(sym); +- flags = sym->flags; +- expr_list_for_each_sym(prop->expr, e, choice_sym) +- if (choice_sym->visible != no) +- flags &= choice_sym->flags; +- sym->flags &= flags | ~SYMBOL_DEF_USER; + } + + for_all_symbols(i, sym) { +@@ -388,43 +465,300 @@ + return 0; + } + ++/* ++ * Kconfig configuration printer ++ * ++ * This printer is used when generating the resulting configuration after ++ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by ++ * passing a non-NULL argument to the printer. ++ * ++ */ ++static void ++kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) ++{ ++ ++ switch (sym->type) { ++ case S_BOOLEAN: ++ case S_TRISTATE: ++ if (*value == 'n') { ++ bool skip_unset = (arg != NULL); ++ ++ if (!skip_unset) ++ fprintf(fp, "# %s%s is not set\n", ++ CONFIG_, sym->name); ++ return; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); ++} ++ ++static void ++kconfig_print_comment(FILE *fp, const char *value, void *arg) ++{ ++ const char *p = value; ++ size_t l; ++ ++ for (;;) { ++ l = strcspn(p, "\n"); ++ fprintf(fp, "#"); ++ if (l) { ++ fprintf(fp, " "); ++ xfwrite(p, l, 1, fp); ++ p += l; ++ } ++ fprintf(fp, "\n"); ++ if (*p++ == '\0') ++ break; ++ } ++} ++ ++static struct conf_printer kconfig_printer_cb = ++{ ++ .print_symbol = kconfig_print_symbol, ++ .print_comment = kconfig_print_comment, ++}; ++ ++/* ++ * Header printer ++ * ++ * This printer is used when generating the `include/generated/autoconf.h' file. ++ */ ++static void ++header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) ++{ ++ ++ switch (sym->type) { ++ case S_BOOLEAN: ++ case S_TRISTATE: { ++ const char *suffix = ""; ++ ++ switch (*value) { ++ case 'n': ++ break; ++ case 'm': ++ suffix = "_MODULE"; ++ /* fall through */ ++ default: ++ fprintf(fp, "#define %s%s%s 1\n", ++ CONFIG_, sym->name, suffix); ++ } ++ break; ++ } ++ case S_HEX: { ++ const char *prefix = ""; ++ ++ if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) ++ prefix = "0x"; ++ fprintf(fp, "#define %s%s %s%s\n", ++ CONFIG_, sym->name, prefix, value); ++ break; ++ } ++ case S_STRING: ++ case S_INT: ++ fprintf(fp, "#define %s%s %s\n", ++ CONFIG_, sym->name, value); ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++static void ++header_print_comment(FILE *fp, const char *value, void *arg) ++{ ++ const char *p = value; ++ size_t l; ++ ++ fprintf(fp, "/*\n"); ++ for (;;) { ++ l = strcspn(p, "\n"); ++ fprintf(fp, " *"); ++ if (l) { ++ fprintf(fp, " "); ++ xfwrite(p, l, 1, fp); ++ p += l; ++ } ++ fprintf(fp, "\n"); ++ if (*p++ == '\0') ++ break; ++ } ++ fprintf(fp, " */\n"); ++} ++ ++static struct conf_printer header_printer_cb = ++{ ++ .print_symbol = header_print_symbol, ++ .print_comment = header_print_comment, ++}; ++ ++/* ++ * Tristate printer ++ * ++ * This printer is used when generating the `include/config/tristate.conf' file. ++ */ ++static void ++tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) ++{ ++ ++ if (sym->type == S_TRISTATE && *value != 'n') ++ fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); ++} ++ ++static struct conf_printer tristate_printer_cb = ++{ ++ .print_symbol = tristate_print_symbol, ++ .print_comment = kconfig_print_comment, ++}; ++ ++static void conf_write_symbol(FILE *fp, struct symbol *sym, ++ struct conf_printer *printer, void *printer_arg) ++{ ++ const char *str; ++ ++ switch (sym->type) { ++ case S_OTHER: ++ case S_UNKNOWN: ++ break; ++ case S_STRING: ++ str = sym_get_string_value(sym); ++ str = sym_escape_string_value(str); ++ printer->print_symbol(fp, sym, str, printer_arg); ++ free((void *)str); ++ break; ++ default: ++ str = sym_get_string_value(sym); ++ printer->print_symbol(fp, sym, str, printer_arg); ++ } ++} ++ ++static void ++conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) ++{ ++ char buf[256]; ++ ++ snprintf(buf, sizeof(buf), ++ "\n" ++ "Automatically generated file; DO NOT EDIT.\n" ++ "%s\n", ++ rootmenu.prompt->text); ++ ++ printer->print_comment(fp, buf, printer_arg); ++} ++ ++/* ++ * Write out a minimal config. ++ * All values that has default values are skipped as this is redundant. ++ */ ++int conf_write_defconfig(const char *filename) ++{ ++ struct symbol *sym; ++ struct menu *menu; ++ FILE *out; ++ ++ out = fopen(filename, "w"); ++ if (!out) ++ return 1; ++ ++ sym_clear_all_valid(); ++ ++ /* Traverse all menus to find all relevant symbols */ ++ menu = rootmenu.list; ++ ++ while (menu != NULL) ++ { ++ sym = menu->sym; ++ if (sym == NULL) { ++ if (!menu_is_visible(menu)) ++ goto next_menu; ++ } else if (!sym_is_choice(sym)) { ++ sym_calc_value(sym); ++ if (!(sym->flags & SYMBOL_WRITE)) ++ goto next_menu; ++ sym->flags &= ~SYMBOL_WRITE; ++ /* If we cannot change the symbol - skip */ ++ if (!sym_is_changable(sym)) ++ goto next_menu; ++ /* If symbol equals to default value - skip */ ++ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) ++ goto next_menu; ++ ++ /* ++ * If symbol is a choice value and equals to the ++ * default for a choice - skip. ++ * But only if value is bool and equal to "y" and ++ * choice is not "optional". ++ * (If choice is "optional" then all values can be "n") ++ */ ++ if (sym_is_choice_value(sym)) { ++ struct symbol *cs; ++ struct symbol *ds; ++ ++ cs = prop_get_symbol(sym_get_choice_prop(sym)); ++ ds = sym_choice_default(cs); ++ if (!sym_is_optional(cs) && sym == ds) { ++ if ((sym->type == S_BOOLEAN) && ++ sym_get_tristate_value(sym) == yes) ++ goto next_menu; ++ } ++ } ++ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); ++ } ++next_menu: ++ if (menu->list != NULL) { ++ menu = menu->list; ++ } ++ else if (menu->next != NULL) { ++ menu = menu->next; ++ } else { ++ while ((menu = menu->parent)) { ++ if (menu->next != NULL) { ++ menu = menu->next; ++ break; ++ } ++ } ++ } ++ } ++ fclose(out); ++ return 0; ++} ++ + int conf_write(const char *name) + { + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; +- char dirname[128], tmpname[128], newname[128]; +- int type, l; + const char *str; +- time_t now; +- int use_timestamp = 1; +- char *env; ++ char tmpname[PATH_MAX+1], newname[PATH_MAX+1]; ++ char *env, *dirname = NULL; + +- dirname[0] = 0; +- if (name == NULL) +- name = conf_get_configname(); + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { +- strcpy(dirname, name); ++ dirname = strndup(name, strlen(name) + 1); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; +- memcpy(dirname, name, size); +- dirname[size] = 0; ++ dirname = strndup(name, size); + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; +- } else +- basename = conf_get_configname(); +- ++ } else { ++ dirname = strdup(conf_get_configname()); ++ basename = strdup(base_name(dirname)); ++ dirname = dir_name(dirname); ++ } + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { +@@ -434,24 +768,11 @@ + *tmpname = 0; + out = fopen(newname, "w"); + } ++ free(dirname); + if (!out) + return 1; + +- sym = sym_lookup("VERSION", 0); +- sym_calc_value(sym); +- time(&now); +- env = getenv("KCONFIG_NOTIMESTAMP"); +- if (env && *env) +- use_timestamp = 0; +- +- fprintf(out, _("#\n" +- "# Automatically generated make config: don't edit\n" +- "# Version: %s\n" +- "%s%s" +- "#\n"), +- sym_get_string_value(sym), +- use_timestamp ? "# " : "", +- use_timestamp ? ctime(&now) : ""); ++ conf_write_heading(out, &kconfig_printer_cb, NULL); + + if (!conf_get_changed()) + sym_clear_all_valid(); +@@ -472,56 +793,11 @@ + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; +- type = sym->type; +- if (type == S_TRISTATE) { +- sym_calc_value(modules_sym); +- if (modules_sym->curr.tri == no) +- type = S_BOOLEAN; +- } +- switch (type) { +- case S_BOOLEAN: +- case S_TRISTATE: +- switch (sym_get_tristate_value(sym)) { +- case no: +- fprintf(out, "# %s is not set\n", sym->name); +- break; +- case mod: +- fprintf(out, "%s=m\n", sym->name); +- break; +- case yes: +- fprintf(out, "%s=y\n", sym->name); +- break; +- } +- break; +- case S_STRING: +- str = sym_get_string_value(sym); +- fprintf(out, "%s=\"", sym->name); +- while (1) { +- l = strcspn(str, "\"\\"); +- if (l) { +- fwrite(str, l, 1, out); +- str += l; +- } +- if (!*str) +- break; +- fprintf(out, "\\%c", *str++); +- } +- fputs("\"\n", out); +- break; +- case S_HEX: +- str = sym_get_string_value(sym); +- if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { +- fprintf(out, "%s=%s\n", sym->name, str); +- break; +- } +- case S_INT: +- str = sym_get_string_value(sym); +- fprintf(out, "%s=%s\n", sym->name, str); +- break; +- } ++ ++ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } + +- next: ++next: + if (menu->list) { + menu = menu->list; + continue; +@@ -538,38 +814,39 @@ + fclose(out); + + if (*tmpname) { +- strcat(dirname, basename); ++ dirname = strndup(basename, strlen(basename) + 4); + strcat(dirname, ".old"); + rename(newname, dirname); ++ free(dirname); + if (rename(tmpname, newname)) + return 1; + } + +- printf(_("#\n" +- "# configuration written to %s\n" +- "#\n"), newname); ++ conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; + } + +-int conf_split_config(void) ++static int conf_split_config(void) + { +- char *name, path[128], opwd[512]; ++ const char *name; ++ char path[PATH_MAX+1], opwd[PATH_MAX+1]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + +- name = getenv("KCONFIG_AUTOCONFIG"); +- if (!name) +- name = "include/config/auto.conf"; +- conf_read_simple(name, S_DEF_AUTO); +- + if (getcwd(opwd, sizeof(opwd)) == NULL) + return 1; +- if (chdir(dirname(strdup(name)))) ++ name = conf_get_autoconfig_name(); ++ conf_read_simple(name, S_DEF_AUTO); ++ ++ strcpy(path, name); ++ dir_name(path); ++ ++ if (chdir(path)) + return 1; + + res = 0; +@@ -671,126 +948,85 @@ + + int conf_write_autoconf(void) + { +- char opwd[512]; + struct symbol *sym; +- const char *str; +- char *name; +- FILE *out, *out_h; +- time_t now; +- int i, l; ++ const char *name; ++ char cfg_fname[PATH_MAX+1], tristate_fname[PATH_MAX+1], ++ cfgh_fname[PATH_MAX+1]; ++ char *dirname; ++ FILE *out, *tristate, *out_h; ++ int i; + +- if (getcwd(opwd, sizeof(opwd)) == NULL) +- return 1; +- if (chdir(dirname(strdup(conf_get_configname())))) +- return 1; + sym_clear_all_valid(); + +- file_write_dep("include/config/auto.conf.cmd"); ++ sprintf(cfg_fname, "%s.cmd", conf_get_autoconfig_name()); ++ file_write_dep(cfg_fname); + + if (conf_split_config()) + return 1; + +- out = fopen(".tmpconfig", "w"); ++ dirname = dir_name(strdup(conf_get_configname())); ++ sprintf(cfg_fname, "%s.tmpconfig", dirname); ++ sprintf(tristate_fname, "%s.tmpconfig_tristate", dirname); ++ sprintf(cfgh_fname, "%s.tmpconfig.h", dirname); ++ free(dirname); ++ ++ out = fopen(cfg_fname, "w"); + if (!out) + return 1; + +- out_h = fopen(".tmpconfig.h", "w"); ++ tristate = fopen(tristate_fname, "w"); ++ if (!tristate) { ++ fclose(out); ++ return 1; ++ } ++ ++ out_h = fopen(cfgh_fname, "w"); + if (!out_h) { + fclose(out); ++ fclose(tristate); + return 1; + } + +- sym = sym_lookup("VERSION", 0); +- sym_calc_value(sym); +- time(&now); +- fprintf(out, "#\n" +- "# Automatically generated make config: don't edit\n" +- "# Version: %s\n" +- "# %s" +- "#\n", +- sym_get_string_value(sym), ctime(&now)); +- fprintf(out_h, "/*\n" +- " * Automatically generated C config: don't edit\n" +- " * Version: %s\n" +- " * %s" +- " */\n" +- "#define AUTOCONF_INCLUDED\n", +- sym_get_string_value(sym), ctime(&now)); ++ conf_write_heading(out, &kconfig_printer_cb, NULL); ++ ++ conf_write_heading(tristate, &tristate_printer_cb, NULL); ++ ++ conf_write_heading(out_h, &header_printer_cb, NULL); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; +- switch (sym->type) { +- case S_BOOLEAN: +- case S_TRISTATE: +- switch (sym_get_tristate_value(sym)) { +- case no: +- break; +- case mod: +- fprintf(out, "CONFIG_%s=m\n", sym->name); +- fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); +- break; +- case yes: +- fprintf(out, "%s=y\n", sym->name); +- fprintf(out_h, "#define %s 1\n", sym->name); +- break; +- } +- break; +- case S_STRING: +- str = sym_get_string_value(sym); +- fprintf(out, "%s=\"", sym->name); +- fprintf(out_h, "#define %s \"", sym->name); +- while (1) { +- l = strcspn(str, "\"\\"); +- if (l) { +- fwrite(str, l, 1, out); +- fwrite(str, l, 1, out_h); +- str += l; +- } +- if (!*str) +- break; +- fprintf(out, "\\%c", *str); +- fprintf(out_h, "\\%c", *str); +- str++; +- } +- fputs("\"\n", out); +- fputs("\"\n", out_h); +- break; +- case S_HEX: +- str = sym_get_string_value(sym); +- if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { +- fprintf(out, "%s=%s\n", sym->name, str); +- fprintf(out_h, "#define %s 0x%s\n", sym->name, str); +- break; +- } +- case S_INT: +- str = sym_get_string_value(sym); +- fprintf(out, "%s=%s\n", sym->name, str); +- fprintf(out_h, "#define %s %s\n", sym->name, str); +- break; +- default: +- break; +- } ++ ++ /* write symbol to auto.conf, tristate and header files */ ++ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); ++ ++ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); ++ ++ conf_write_symbol(out_h, sym, &header_printer_cb, NULL); + } + fclose(out); ++ fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) +- name = "include/config/autoconf.h"; +- if (rename(".tmpconfig.h", name)) ++ name = "include/generated/autoconf.h"; ++ if (rename(cfgh_fname, name)) + return 1; +- name = getenv("KCONFIG_AUTOCONFIG"); ++ name = getenv("KCONFIG_TRISTATE"); + if (!name) +- name = "include/config/auto.conf"; ++ name = "include/config/tristate.conf"; ++ if (rename(tristate_fname, name)) ++ return 1; ++ name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ +- if (rename(".tmpconfig", name)) ++ if (rename(cfg_fname, name)) + return 1; +- chdir(opwd); ++ + return 0; + } + +@@ -821,20 +1057,131 @@ + conf_changed_callback = fn; + } + ++static bool randomize_choice_values(struct symbol *csym) ++{ ++ struct property *prop; ++ struct symbol *sym; ++ struct expr *e; ++ int cnt, def; + +-void conf_set_all_new_symbols(enum conf_def_mode mode) ++ /* ++ * If choice is mod then we may have more items selected ++ * and if no then no-one. ++ * In both cases stop. ++ */ ++ if (csym->curr.tri != yes) ++ return false; ++ ++ prop = sym_get_choice_prop(csym); ++ ++ /* count entries in choice block */ ++ cnt = 0; ++ expr_list_for_each_sym(prop->expr, e, sym) ++ cnt++; ++ ++ /* ++ * find a random value and set it to yes, ++ * set the rest to no so we have only one set ++ */ ++ def = (rand() % cnt); ++ ++ cnt = 0; ++ expr_list_for_each_sym(prop->expr, e, sym) { ++ if (def == cnt++) { ++ sym->def[S_DEF_USER].tri = yes; ++ csym->def[S_DEF_USER].val = sym; ++ } ++ else { ++ sym->def[S_DEF_USER].tri = no; ++ } ++ sym->flags |= SYMBOL_DEF_USER; ++ /* clear VALID to get value calculated */ ++ sym->flags &= ~SYMBOL_VALID; ++ } ++ csym->flags |= SYMBOL_DEF_USER; ++ /* clear VALID to get value calculated */ ++ csym->flags &= ~(SYMBOL_VALID); ++ ++ return true; ++} ++ ++void set_all_choice_values(struct symbol *csym) + { +- struct symbol *sym, *csym; + struct property *prop; ++ struct symbol *sym; + struct expr *e; +- int i, cnt, def; ++ ++ prop = sym_get_choice_prop(csym); ++ ++ /* ++ * Set all non-assinged choice values to no ++ */ ++ expr_list_for_each_sym(prop->expr, e, sym) { ++ if (!sym_has_value(sym)) ++ sym->def[S_DEF_USER].tri = no; ++ } ++ csym->flags |= SYMBOL_DEF_USER; ++ /* clear VALID to get value calculated */ ++ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); ++} ++ ++bool conf_set_all_new_symbols(enum conf_def_mode mode) ++{ ++ struct symbol *sym, *csym; ++ int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y ++ * pty: probability of tristate = y ++ * ptm: probability of tristate = m ++ */ ++ ++ pby = 50; pty = ptm = 33; /* can't go as the default in switch-case ++ * below, otherwise gcc whines about ++ * -Wmaybe-uninitialized */ ++ if (mode == def_random) { ++ int n, p[3]; ++ char *env = getenv("KCONFIG_PROBABILITY"); ++ n = 0; ++ while( env && *env ) { ++ char *endp; ++ int tmp = strtol( env, &endp, 10 ); ++ if( tmp >= 0 && tmp <= 100 ) { ++ p[n++] = tmp; ++ } else { ++ errno = ERANGE; ++ perror( "KCONFIG_PROBABILITY" ); ++ exit( 1 ); ++ } ++ env = (*endp == ':') ? endp+1 : endp; ++ if( n >=3 ) { ++ break; ++ } ++ } ++ switch( n ) { ++ case 1: ++ pby = p[0]; ptm = pby/2; pty = pby-ptm; ++ break; ++ case 2: ++ pty = p[0]; ptm = p[1]; pby = pty + ptm; ++ break; ++ case 3: ++ pby = p[0]; pty = p[1]; ptm = p[2]; ++ break; ++ } ++ ++ if( pty+ptm > 100 ) { ++ errno = ERANGE; ++ perror( "KCONFIG_PROBABILITY" ); ++ exit( 1 ); ++ } ++ } ++ bool has_changed = false; + + for_all_symbols(i, sym) { +- if (sym_has_value(sym)) ++ if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: ++ has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; +@@ -846,7 +1193,15 @@ + sym->def[S_DEF_USER].tri = no; + break; + case def_random: +- sym->def[S_DEF_USER].tri = (tristate)(rand() % 3); ++ sym->def[S_DEF_USER].tri = no; ++ cnt = rand() % 100; ++ if (sym->type == S_TRISTATE) { ++ if (cnt < pty) ++ sym->def[S_DEF_USER].tri = yes; ++ else if (cnt < (pty+ptm)) ++ sym->def[S_DEF_USER].tri = mod; ++ } else if (cnt < pby) ++ sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; +@@ -862,51 +1217,35 @@ + + sym_clear_all_valid(); + +- if (mode != def_random) +- return; + /* + * We have different type of choice blocks. +- * If curr.tri equal to mod then we can select several ++ * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. +- * If curr.tri equal yes then only one symbol can be ++ * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ ++ if (mode != def_random) { ++ for_all_symbols(i, csym) { ++ if ((sym_is_choice(csym) && !sym_has_value(csym)) || ++ sym_is_choice_value(csym)) ++ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; ++ } ++ } ++ + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); +- +- if (csym->curr.tri != yes) +- continue; +- +- prop = sym_get_choice_prop(csym); +- +- /* count entries in choice block */ +- cnt = 0; +- expr_list_for_each_sym(prop->expr, e, sym) +- cnt++; +- +- /* +- * find a random value and set it to yes, +- * set the rest to no so we have only one set +- */ +- def = (rand() % cnt); +- +- cnt = 0; +- expr_list_for_each_sym(prop->expr, e, sym) { +- if (def == cnt++) { +- sym->def[S_DEF_USER].tri = yes; +- csym->def[S_DEF_USER].val = sym; +- } +- else { +- sym->def[S_DEF_USER].tri = no; +- } ++ if (mode == def_random) ++ has_changed = randomize_choice_values(csym); ++ else { ++ set_all_choice_values(csym); ++ has_changed = true; + } +- csym->flags |= SYMBOL_DEF_USER; +- /* clear VALID to get value calculated */ +- csym->flags &= ~(SYMBOL_VALID); + } ++ ++ return has_changed; + } +diff -Nur uClibc-0.9.33.2/extra/config/expr.c uClibc-git/extra/config/expr.c +--- uClibc-0.9.33.2/extra/config/expr.c 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/extra/config/expr.c 2014-02-03 12:32:56.000000000 +0100 +@@ -7,15 +7,13 @@ + #include + #include + +-#define LKC_DIRECT_LINK + #include "lkc.h" + + #define DEBUG_EXPR 0 + + struct expr *expr_alloc_symbol(struct symbol *sym) + { +- struct expr *e = malloc(sizeof(*e)); +- memset(e, 0, sizeof(*e)); ++ struct expr *e = xcalloc(1, sizeof(*e)); + e->type = E_SYMBOL; + e->left.sym = sym; + return e; +@@ -23,8 +21,7 @@ + + struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) + { +- struct expr *e = malloc(sizeof(*e)); +- memset(e, 0, sizeof(*e)); ++ struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.expr = ce; + return e; +@@ -32,8 +29,7 @@ + + struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) + { +- struct expr *e = malloc(sizeof(*e)); +- memset(e, 0, sizeof(*e)); ++ struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.expr = e1; + e->right.expr = e2; +@@ -42,8 +38,7 @@ + + struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) + { +- struct expr *e = malloc(sizeof(*e)); +- memset(e, 0, sizeof(*e)); ++ struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.sym = s1; + e->right.sym = s2; +@@ -64,14 +59,14 @@ + return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; + } + +-struct expr *expr_copy(struct expr *org) ++struct expr *expr_copy(const struct expr *org) + { + struct expr *e; + + if (!org) + return NULL; + +- e = malloc(sizeof(*org)); ++ e = xmalloc(sizeof(*org)); + memcpy(e, org, sizeof(*org)); + switch (org->type) { + case E_SYMBOL: +@@ -348,7 +343,7 @@ + /* + * e1 || e2 -> ? + */ +-struct expr *expr_join_or(struct expr *e1, struct expr *e2) ++static struct expr *expr_join_or(struct expr *e1, struct expr *e2) + { + struct expr *tmp; + struct symbol *sym1, *sym2; +@@ -412,7 +407,7 @@ + return NULL; + } + +-struct expr *expr_join_and(struct expr *e1, struct expr *e2) ++static struct expr *expr_join_and(struct expr *e1, struct expr *e2) + { + struct expr *tmp; + struct symbol *sym1, *sym2; +@@ -1013,6 +1008,48 @@ + #endif + } + ++static inline struct expr * ++expr_get_leftmost_symbol(const struct expr *e) ++{ ++ ++ if (e == NULL) ++ return NULL; ++ ++ while (e->type != E_SYMBOL) ++ e = e->left.expr; ++ ++ return expr_copy(e); ++} ++ ++/* ++ * Given expression `e1' and `e2', returns the leaf of the longest ++ * sub-expression of `e1' not containing 'e2. ++ */ ++struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) ++{ ++ struct expr *ret; ++ ++ switch (e1->type) { ++ case E_OR: ++ return expr_alloc_and( ++ expr_simplify_unmet_dep(e1->left.expr, e2), ++ expr_simplify_unmet_dep(e1->right.expr, e2)); ++ case E_AND: { ++ struct expr *e; ++ e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); ++ e = expr_eliminate_dups(e); ++ ret = (!expr_eq(e, e1)) ? e1 : NULL; ++ expr_free(e); ++ break; ++ } ++ default: ++ ret = e1; ++ break; ++ } ++ ++ return expr_get_leftmost_symbol(ret); ++} ++ + void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) + { + if (!e) { +@@ -1087,7 +1124,7 @@ + + static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) + { +- fwrite(str, strlen(str), 1, data); ++ xfwrite(str, strlen(str), 1, data); + } + + void expr_fprint(struct expr *e, FILE *out) +@@ -1097,7 +1134,32 @@ + + static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) + { +- str_append((struct gstr*)data, str); ++ struct gstr *gs = (struct gstr*)data; ++ const char *sym_str = NULL; ++ ++ if (sym) ++ sym_str = sym_get_string_value(sym); ++ ++ if (gs->max_width) { ++ unsigned extra_length = strlen(str); ++ const char *last_cr = strrchr(gs->s, '\n'); ++ unsigned last_line_length; ++ ++ if (sym_str) ++ extra_length += 4 + strlen(sym_str); ++ ++ if (!last_cr) ++ last_cr = gs->s; ++ ++ last_line_length = strlen(gs->s) - (last_cr - gs->s); ++ ++ if ((last_line_length + extra_length) > gs->max_width) ++ str_append(gs, "\\\n"); ++ } ++ ++ str_append(gs, str); ++ if (sym && sym->type != S_UNKNOWN) ++ str_printf(gs, " [=%s]", sym_str); + } + + void expr_gstr_print(struct expr *e, struct gstr *gs) +diff -Nur uClibc-0.9.33.2/extra/config/expr.h uClibc-git/extra/config/expr.h +--- uClibc-0.9.33.2/extra/config/expr.h 2012-05-15 09:20:09.000000000 +0200 ++++ uClibc-git/extra/config/expr.h 2014-02-03 12:32:56.000000000 +0100 +@@ -10,7 +10,9 @@ + extern "C" { + #endif + ++#include + #include ++#include "list.h" + #ifndef __cplusplus + #include + #endif +@@ -18,14 +20,10 @@ + struct file { + struct file *next; + struct file *parent; +- char *name; ++ const char *name; + int lineno; +- int flags; + }; + +-#define FILE_BUSY 0x0001 +-#define FILE_SCANNED 0x0002 +- + typedef enum tristate { + no, mod, yes + } tristate; +@@ -83,10 +81,11 @@ + tristate visible; + int flags; + struct property *prop; ++ struct expr_value dir_dep; + struct expr_value rev_dep; + }; + +-#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) ++#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + + #define SYMBOL_CONST 0x0001 /* symbol is const */ + #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ +@@ -107,9 +106,11 @@ + #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ + #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ + ++/* choice values need to be set before calculating this symbol value */ ++#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 ++ + #define SYMBOL_MAXLENGTH 256 +-#define SYMBOL_HASHSIZE 257 +-#define SYMBOL_HASHMASK 0xff ++#define SYMBOL_HASHSIZE 9973 + + /* A property represent the config options that can be associated + * with a config "symbol". +@@ -132,6 +133,7 @@ + P_SELECT, /* select BAR */ + P_RANGE, /* range 7..100 (for a symbol) */ + P_ENV, /* value from environment variable */ ++ P_SYMBOL, /* where a symbol is defined */ + }; + + struct property { +@@ -163,6 +165,7 @@ + struct menu *list; + struct symbol *sym; + struct property *prompt; ++ struct expr *visibility; + struct expr *dep; + unsigned int flags; + char *help; +@@ -174,7 +177,14 @@ + #define MENU_CHANGED 0x0001 + #define MENU_ROOT 0x0002 + +-#ifndef SWIG ++struct jump_key { ++ struct list_head entries; ++ size_t offset; ++ struct menu *target; ++ int index; ++}; ++ ++#define JUMP_NB 9 + + extern struct file *file_list; + extern struct file *current_file; +@@ -190,7 +200,7