Commit 7f60c550 authored by Roman Zippel's avatar Roman Zippel Committed by Linus Torvalds

[PATCH] remove old config tools

This deletes the old config tools and moves Michael's maintainer entry
for them to CREDITS and I added myself for KCONFIG instead.
parent 4e81d4aa
...@@ -533,6 +533,10 @@ S: Tamsui town, Taipei county, ...@@ -533,6 +533,10 @@ S: Tamsui town, Taipei county,
S: Taiwan 251 S: Taiwan 251
S: Republic of China S: Republic of China
N: Michael Elizabeth Chastain
E: mec@shout.net
D: Configure, Menuconfig, xconfig
N: Raymond Chen N: Raymond Chen
E: raymondc@microsoft.com E: raymondc@microsoft.com
D: Author of Configure script D: Author of Configure script
......
...@@ -379,13 +379,6 @@ P: Gergely Madarasz ...@@ -379,13 +379,6 @@ P: Gergely Madarasz
M: Gergely Madarasz <gorgo@itc.hu> M: Gergely Madarasz <gorgo@itc.hu>
S: Supported S: Supported
CONFIGURE, MENUCONFIG, XCONFIG
P: Michael Elizabeth Chastain
M: mec@shout.net
L: kbuild-devel@lists.sourceforge.net
W: http://kbuild.sourceforge.net
S: Maintained
COSA/SRP SYNC SERIAL DRIVER COSA/SRP SYNC SERIAL DRIVER
P: Jan "Yenya" Kasprzak P: Jan "Yenya" Kasprzak
M: kas@fi.muni.cz M: kas@fi.muni.cz
...@@ -942,6 +935,12 @@ L: linux-joystick@atrey.karlin.mff.cuni.cz ...@@ -942,6 +935,12 @@ L: linux-joystick@atrey.karlin.mff.cuni.cz
W: http://www.suse.cz/development/joystick/ W: http://www.suse.cz/development/joystick/
S: Maintained S: Maintained
KCONFIG
P: Roman Zippel
M: zippel@linux-m68k.org
L: kbuild-devel@lists.sourceforge.net
S: Maintained
KERNEL AUTOMOUNTER (AUTOFS) KERNEL AUTOMOUNTER (AUTOFS)
P: H. Peter Anvin P: H. Peter Anvin
M: hpa@zytor.com M: hpa@zytor.com
......
#! /bin/sh
#
# This script is used to configure the Linux kernel.
#
# It was inspired by the challenge in the original Configure script
# to ``do something better'', combined with the actual need to ``do
# something better'' because the old configure script wasn't flexible
# enough.
#
# Raymond Chen was the original author of Configure.
# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
#
# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
# with an empty IFS.
#
# 030995 (storner@osiris.ping.dk) - added support for tri-state answers,
# for selecting modules to compile.
#
# 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
# use with a config.in modified for make menuconfig.
#
# 301195 (boldt@math.ucsb.edu) - added help text support
#
# 281295 Paul Gortmaker - make tri_state functions collapse to boolean
# if module support is not enabled.
#
# 010296 Aaron Ucko (ucko@vax1.rockhurst.edu) - fix int and hex to accept
# arbitrary ranges
#
# 150296 Dick Streefland (dicks@tasking.nl) - report new configuration
# items and ask for a value even when doing a "make oldconfig"
#
# 200396 Tom Dyas (tdyas@eden.rutgers.edu) - when the module option is
# chosen for an item, define the macro <option_name>_MODULE
#
# 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular
# expressions for GNU expr since version 1.15 and up use \? and \+.
#
# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max
# arguments to "int", allow dep_tristate to take a list of dependencies
# rather than just one.
#
# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
# texts.
#
# 102598 Michael Chastain (mec@shout.net) - put temporary files in
# current directory, not in /tmp.
#
# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
# - Improve the exit message (Jeff Ronne).
#
# 7 October 2000, Ghozlane Toumi, <gtoumi@messel.emse.fr>
# added switches for "random" , "all yes" and "all modules"
#
#
# Make sure we're really running bash.
#
# I would really have preferred to write this script in a language with
# better string handling, but alas, bash is the only scripting language
# that I can be reasonable sure everybody has on their linux machine.
#
[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
# Disable filename globbing once and for all.
# Enable function cacheing.
set -f -h
#
# Dummy functions for use with a config.in modified for menuconf
#
function mainmenu_option () {
:
}
function mainmenu_name () {
:
}
function endmenu () {
:
}
#
# returns a random number between 1 and $1
#
function rnd () {
rnd=$[ $RANDOM % $1 + 1 ]
}
#
# randomly chose a number in a config list (LIST_CONFIG_NAME)
# or in a range ( MIN_CONFIG_NAME MAX_CONFIG_NAME )
# ONLY if there is no forced default (and we are in an "auto" mode)
# we are limited by the range of values taken by "$RANDOM"
#
# rndval CONFIG_NAME
#
function rndval () {
[ "$AUTO" != "yes" -o -n "$old" ] && return
def_list=$(eval echo "\${LIST_$1}")
def_min=$(eval echo "\${MIN_$1}")
def_max=$(eval echo "\${MAX_$1}")
if [ -n "$def_list" ]; then
set -- $(echo $def_list | sed 's/,/ /g')
rnd $#
while [ $rnd -le $# ] ; do
def=$1
shift
done
return
fi
if [ -n "$def_min" -a -n "$def_max" ]; then
rnd $[ $def_max - $def_min ]
def=$[ $def_min + $rnd ]
fi
}
#
# help prints the corresponding help text from Configure.help to stdout
#
# help variable
#
function help () {
#first escape regexp special characters in the argument:
var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
#now pick out the right help text:
text=$(cat /dev/null $(find . -name Config.help) |
sed -n "/^$var[ ]*\$/,\${
/^$var[ ]*\$/c\\
${var}:\\
/^#/b
/^[^ ]/q
/<file:\\([^>]*\\)>/s//\\1/g
p
}")
if [ -z "$text" ]
then
echo; echo " Sorry, no help available for this option yet.";echo
else
(echo; echo "$text"; echo) | ${PAGER:-more}
fi
}
#
# readln reads a line into $ans.
#
# readln prompt default oldval
#
function readln () {
if [ "$AUTO" = "yes" ]; then
echo -n "$1"
ans=$2
echo $ans
elif [ "$DEFAULT" = "-d" -a -n "$3" ]; then
echo "$1"
ans=$2
else
echo -n "$1"
[ -z "$3" ] && echo -n "(NEW) "
IFS='@' read ans || exit 1
[ -z "$ans" ] && ans=$2
fi
}
#
# comment does some pretty-printing
#
# comment 'xxx'
#
function comment () {
echo "*"; echo "* $1" ; echo "*"
(echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG
(echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H
}
#
# define_bool sets the value of a boolean argument
#
# define_bool define value
#
function define_bool () {
define_tristate $1 $2
}
function define_tristate () {
case "$2" in
"y")
echo "$1=y" >>$CONFIG
echo "#define $1 1" >>$CONFIG_H
;;
"m")
echo "$1=m" >>$CONFIG
echo "#undef $1" >>$CONFIG_H
echo "#define $1_MODULE 1" >>$CONFIG_H
;;
"n")
echo "# $1 is not set" >>$CONFIG
echo "#undef $1" >>$CONFIG_H
;;
esac
eval "$1=$2"
}
#
# bool processes a boolean argument
#
# bool question define
#
function bool () {
old=$(eval echo "\${$2}")
def=${old:-'n'}
if [ "$AUTO" = "yes" -a -z "$old" ]; then
if [ "$RND" = "-r" ]; then
rnd 2
case $rnd in
"1") def="y" ;;
"2") def="n" ;;
esac
else
def=$DEF_ANS;
fi
fi
case "$def" in
"y" | "m") defprompt="Y/n/?"
def="y"
;;
"n") defprompt="N/y/?"
;;
esac
while :; do
readln "$1 ($2) [$defprompt] " "$def" "$old"
case "$ans" in
[yY] | [yY]es ) define_bool "$2" "y"
break;;
[nN] | [nN]o ) define_bool "$2" "n"
break;;
* ) help "$2"
;;
esac
done
}
#
# tristate processes a tristate argument
#
# tristate question define
#
function tristate () {
if [ "$CONFIG_MODULES" != "y" ]; then
bool "$1" "$2"
else
old=$(eval echo "\${$2}")
def=${old:-'n'}
if [ "$AUTO" = "yes" -a -z "$old" ]; then
if [ "$RND" = "-r" ]; then
rnd 3
case $rnd in
"1") def="y" ;;
"2") def="n" ;;
"3") def="m" ;;
esac
else
def=$DEF_ANS
fi
fi
case "$def" in
"y") defprompt="Y/m/n/?"
;;
"m") defprompt="M/n/y/?"
;;
"n") defprompt="N/y/m/?"
;;
esac
while :; do
readln "$1 ($2) [$defprompt] " "$def" "$old"
case "$ans" in
[yY] | [yY]es ) define_tristate "$2" "y"
break ;;
[nN] | [nN]o ) define_tristate "$2" "n"
break ;;
[mM] ) define_tristate "$2" "m"
break ;;
* ) help "$2"
;;
esac
done
fi
}
#
# dep_tristate processes a tristate argument that depends upon
# another option or options. If any of the options we depend upon is a
# module, then the only allowable options are M or N. If all are Y, then
# this is a normal tristate. This is used in cases where modules
# are nested, and one module requires the presence of something
# else in the kernel.
#
# dep_tristate question define default ...
#
function dep_tristate () {
old=$(eval echo "\${$2}")
def=${old:-'n'}
ques=$1
var=$2
need_module=0
shift 2
while [ $# -gt 0 ]; do
case "$1" in
n)
define_tristate "$var" "n"
return
;;
m)
need_module=1
;;
esac
shift
done
if [ $need_module = 1 ]; then
if [ "$CONFIG_MODULES" = "y" ]; then
if [ "$AUTO" = "yes" -a -z "$old" ]; then
if [ "$RND" = "-r" ]; then
rnd 2
case $rnd in
"1") def="m" ;;
"2") def="n" ;;
esac
else
def=$DEF_ANS
fi
fi
case "$def" in
"y" | "m") defprompt="M/n/?"
def="m"
;;
"n") defprompt="N/m/?"
;;
esac
while :; do
readln "$ques ($var) [$defprompt] " "$def" "$old"
case "$ans" in
[nN] | [nN]o ) define_tristate "$var" "n"
break ;;
[mM] ) define_tristate "$var" "m"
break ;;
[yY] | [yY]es ) echo
echo " This answer is not allowed, because it is not consistent with"
echo " your other choices."
echo " This driver depends on another one which you chose to compile"
echo " as a module. This means that you can either compile this one"
echo " as a module as well (with M) or leave it out altogether (N)."
echo
;;
* ) help "$var"
;;
esac
done
fi
else
tristate "$ques" "$var"
fi
}
function dep_bool () {
ques=$1
var=$2
shift 2
while [ $# -gt 0 ]; do
case "$1" in
m | n)
define_bool "$var" "n"
return
;;
esac
shift
done
bool "$ques" "$var"
}
function dep_mbool () {
ques=$1
var=$2
shift 2
while [ $# -gt 0 ]; do
case "$1" in
n)
define_bool "$var" "n"
return
;;
esac
shift
done
bool "$ques" "$var"
}
#
# define_int sets the value of a integer argument
#
# define_int define value
#
function define_int () {
echo "$1=$2" >>$CONFIG
echo "#define $1 ($2)" >>$CONFIG_H
eval "$1=$2"
}
#
# int processes an integer argument with optional limits
#
# int question define default
#
function int () {
old=$(eval echo "\${$2}")
def=${old:-$3}
rndval $2
while :; do
readln "$1 ($2) [$def] " "$def" "$old"
if expr "$ans" : '[0-9]*$' > /dev/null; then
define_int "$2" "$ans"
break
else
help "$2"
fi
done
}
#
# define_hex sets the value of a hexadecimal argument
#
# define_hex define value
#
function define_hex () {
echo "$1=$2" >>$CONFIG
echo "#define $1 0x${2#*[x,X]}" >>$CONFIG_H
eval "$1=$2"
}
#
# hex processes an hexadecimal argument
#
# hex question define default
#
function hex () {
old=$(eval echo "\${$2}")
def=${old:-$3}
def=${def#*[x,X]}
rndval $2
while :; do
readln "$1 ($2) [$def] " "$def" "$old"
ans=${ans#*[x,X]}
if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
define_hex "$2" "$ans"
break
else
help "$2"
fi
done
}
#
# define_string sets the value of a string argument
#
# define_string define value
#
function define_string () {
echo "$1=\"$2\"" >>$CONFIG
echo "#define $1 \"$2\"" >>$CONFIG_H
eval "$1=\"$2\""
}
#
# string processes a string argument
#
# string question define default
#
function string () {
old=$(eval echo "\${$2}")
def=${old:-$3}
while :; do
if [ "$old" = "?" ]; then
readln "$1 ($2) [$def] " "$def" ""
else
readln "$1 ($2) [$def] " "$def" "$old"
fi
if [ "$ans" = "?" ]; then
help "$2"
else
break
fi
done
define_string "$2" "$ans"
}
#
# choice processes a choice list (1-out-of-n)
#
# choice question choice-list default
#
# The choice list has a syntax of:
# NAME WHITESPACE VALUE { WHITESPACE NAME WHITESPACE VALUE }
# The user may enter any unique prefix of one of the NAMEs and
# choice will define VALUE as if it were a boolean option.
# VALUE must be in all uppercase. Normally, VALUE is of the
# form CONFIG_<something>. Thus, if the user selects <something>,
# the CPP symbol CONFIG_<something> will be defined and the
# shell variable CONFIG_<something> will be set to "y".
#
function choice () {
question="$1"
choices="$2"
old=
def=$3
# determine default answer:
names=""
set -- $choices
firstvar=$2
while [ -n "$2" ]; do
if [ -n "$names" ]; then
names="$names, $1"
else
names="$1"
fi
if [ "$(eval echo \"\${$2}\")" = "y" ]; then
old=$1
def=$1
fi
shift; shift
done
if [ "$RND" = "-r" -a -z "$old" ] ; then
set -- $choices
rnd $#
while [ $rnd -le $# ] ; do
def=$1
shift ; shift
done
fi
val=""
while [ -z "$val" ]; do
ambg=n
readln "$question ($names) [$def] " "$def" "$old"
ans=$(echo $ans | tr a-z A-Z)
set -- $choices
while [ -n "$1" ]; do
name=$(echo $1 | tr a-z A-Z)
case "$name" in
"$ans"* | */"$ans"* )
case "$name" in
"$ans" | */"$ans"/* | \
"$ans"/* | */"$ans" )
val="$2"
break # exact match
;;
esac
if [ -n "$val" ]; then
echo;echo \
" Sorry, \"$ans\" is ambiguous; please enter a longer string."
echo
val=""
ambg=y
break
else
val="$2"
fi;;
esac
shift; shift
done
if [ "$val" = "" -a "$ambg" = "n" ]; then
help "$firstvar"
fi
done
set -- $choices
while [ -n "$2" ]; do
if [ "$2" = "$val" ]; then
echo " defined $val"
define_bool "$2" "y"
else
define_bool "$2" "n"
fi
shift; shift
done
}
CONFIG=.tmpconfig
CONFIG_H=.tmpconfig.h
FORCE_DEFAULT=.force_default
trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
#
# Make sure we start out with a clean slate.
#
echo "#" > $CONFIG
echo "# Automatically generated make config: don't edit" >> $CONFIG
echo "#" >> $CONFIG
echo "/*" > $CONFIG_H
echo " * Automatically generated C config: don't edit" >> $CONFIG_H
echo " */" >> $CONFIG_H
echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
DEFAULT=""
if [ "$1" = "-d" ] ; then
DEFAULT="-d"
shift
fi
RND=""
DEF_ANS=""
AUTO=""
case "$1" in
-r) RND="-r" ; AUTO="yes" ; shift ;;
-y) DEF_ANS="y" ; AUTO="yes" ; shift ;;
-m) DEF_ANS="m" ; AUTO="yes" ; shift ;;
-n) DEF_ANS="n" ; AUTO="yes" ; shift ;;
esac
CONFIG_IN=./config.in
if [ "$1" != "" ] ; then
CONFIG_IN=$1
fi
for DEFAULTS in .config /lib/modules/`uname -r`/.config /etc/kernel-config /boot/config-`uname -r` arch/$ARCH/defconfig
do
[ -r $DEFAULTS ] && break
done
if [ "$AUTO" != "yes" ]; then
if [ -f $DEFAULTS ]; then
echo "#"
echo "# Using defaults found in" $DEFAULTS
echo "#"
. $DEFAULTS
sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
. .config-is-not.$$
rm .config-is-not.$$
else
echo "#"
echo "# No defaults found"
echo "#"
fi
else
if [ -f $FORCE_DEFAULT ]; then
echo "#"
echo "# Forcing defaults found in $FORCE_DEFAULT"
echo "#"
sed -e '
s/# \(CONFIG_[^ ]*\) is not.*/\1=n/;
s/# range \(CONFIG_[^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\)/MIN_\1=\2; MAX_\1=\3/;
s/# list \(CONFIG_[^ ]*\) \([^ ][^ ]*\)/LIST_\1=\2/
' <$FORCE_DEFAULT >.default_val.$$
. .default_val.$$
rm .default_val.$$
else
echo "#"
echo "# No defaults found"
echo "#"
fi
fi
. $CONFIG_IN
rm -f .config.old
if [ -f .config ]; then
mv .config .config.old
fi
mv .tmpconfig .config
mv .tmpconfig.h include/linux/autoconf.h
echo
echo "*** End of Linux kernel configuration."
echo "*** Check the top-level Makefile for additional configuration."
if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then
echo "*** Next, you must run 'make dep'."
else
echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'."
fi
echo
exit 0
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
# include/config/... # include/config/...
# docproc: Preprocess .tmpl file in order to generate .sgml documentation # docproc: Preprocess .tmpl file in order to generate .sgml documentation
# conmakehash: Create arrays for initializing the kernel console tables # conmakehash: Create arrays for initializing the kernel console tables
# tkparse: Used by xconfig
EXTRA_TARGETS := fixdep split-include docproc conmakehash EXTRA_TARGETS := fixdep split-include docproc conmakehash
...@@ -23,33 +22,10 @@ KBUILD_BUILTIN := 1 ...@@ -23,33 +22,10 @@ KBUILD_BUILTIN := 1
# can't do it # can't do it
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
host-progs := fixdep split-include conmakehash docproc tkparse host-progs := fixdep split-include conmakehash docproc
tkparse-objs := tkparse.o tkcond.o tkgen.o
clean-files := kconfig.tk
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
# In reality kconfig.tk should depend on all Config.in files,
# but it is not worth the effort to generate the dependencies.
# The alternative solution to always generate it is fairly fast.
# FORCE it to remake
$(obj)/kconfig.tk: $(srctree)/arch/$(ARCH)/config.in $(obj)/tkparse FORCE
@echo ' Generating $@'
@( \
if [ -f /usr/local/bin/wish ]; then \
echo '#!'"/usr/local/bin/wish -f"; \
else \
echo '#!'"/usr/bin/wish -f"; \
fi; \
cat $(src)/header.tk; \
$(obj)/tkparse < $<; \
echo "set defaults \"arch/${ARCH}/defconfig\""; \
echo "set ARCH \"${ARCH}\""; \
cat $(src)/tail.tk; \
) > $@
@chmod 755 $@
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Targets hardcoded and wellknow in top-level makefile # Targets hardcoded and wellknow in top-level makefile
...@@ -58,5 +34,5 @@ lxdialog: ...@@ -58,5 +34,5 @@ lxdialog:
$(call descend,scripts/lxdialog,) $(call descend,scripts/lxdialog,)
# fixdep is needed to compile other host programs # fixdep is needed to compile other host programs
$(obj)/split-include $(obj)/docproc $(addprefix $(obj)/,$(tkparse-objs)) \ $(obj)/split-include $(obj)/docproc \
$(obj)/conmakehash lxdialog: $(obj)/fixdep $(obj)/conmakehash lxdialog: $(obj)/fixdep
#! /bin/sh
#
# This script is used to configure the linux kernel.
#
# It was inspired by a desire to not have to hit <enter> 9 million times
# or startup the X server just to change a single kernel parameter.
#
# This script attempts to parse the configuration files, which are
# scattered throughout the kernel source tree, and creates a temporary
# set of mini scripts which are in turn used to create nested menus and
# radiolists.
#
# It uses a very modified/mutilated version of the "dialog" utility
# written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible
# for this script or the version of dialog used by this script.
# Please do not contact him with questions. The official version of
# dialog is available at sunsite.unc.edu or a sunsite mirror.
#
# Portions of this script were borrowed from the original Configure
# script.
#
# William Roadcap was the original author of Menuconfig.
# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
#
# 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for
# new bool, tristate and dep_tristate parameters from the defconfig file.
# new configuration parameters are marked with '(NEW)' as in make config.
#
# 180697 Bernhard Kaindl (bkaindl@netway.at) - added the needed support
# for string options. They are handled like the int and hex options.
#
# 081297 Pavel Machek (pavel@atrey.karlin.mff.cuni.cz) - better error
# handling
#
# 131197 Michael Chastain (mec@shout.net) - output all lines for a
# choice list, not just the selected one. This makes the output
# the same as Configure output, which is important for smart config
# dependencies.
#
# 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft.
#
# 221297 Michael Chastain (mec@shout.net) - make define_bool actually
# define its arguments so that later tests on them work right.
#
# 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command
# (complement existing value) when used on virgin uninitialized variables.
#
# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
# texts.
#
# 12 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
# Remove a /tmp security hole in get_def (also makes it faster).
# Give uninitialized variables canonical values rather than null value.
# Change a lot of places to call set_x_info uniformly.
# Take out message about preparing version (old sound driver cruft).
#
# 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
# When an error occurs, actually display the error message as well as
# our comments thereon.
#
# 31 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
# Fix mod_bool to honor $CONFIG_MODULES.
# Fix dep_tristate to call define_bool when dependency is "n".
#
# 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
# Blow away lxdialog.scrltmp on entry to activate_menu. This protects
# against people who use commands like ' ' to select menus.
#
# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
# - Improve the exit message (Jeff Ronne).
#
# 06 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
# - Support for multiple conditions in dep_tristate().
# - Implemented new functions: define_tristate(), define_int(), define_hex(),
# define_string(), dep_bool().
#
# 12 November 2001, Keith Owens <kaos@ocs.com.au>
# Escape double quotes on eval so the quotes are still there on the second
# evaluation, required to handle strings with special characters.
#
#
# Change this to TRUE if you prefer all kernel options listed
# in a single menu rather than the standard menu hierarchy.
#
single_menu_mode=
#
# Make sure we're really running bash.
#
[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
#
# Cache function definitions, turn off posix compliance
#
set -h +o posix
# Given a configuration variable, set the global variable $x to its value,
# and the global variable $info to the string " (NEW)" if this is a new
# variable.
#
# This function looks for: (1) the current value, or (2) the default value
# from the arch-dependent defconfig file, or (3) a default passed by the caller.
function set_x_info () {
eval x=\$$1
if [ -z "$x" ]; then
eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig`
eval x=\${$1:-\"$2\"}
eval $1=$x
eval INFO_$1="' (NEW)'"
fi
eval info=\"\$INFO_$1\"
}
#
# Load the functions used by the config.in files.
#
# I do this because these functions must be redefined depending
# on whether they are being called for interactive use or for
# saving a configuration to a file.
#
# Thank the heavens bash supports nesting function definitions.
#
load_functions () {
#
# Additional comments
#
function comment () {
comment_ctr=$[ comment_ctr + 1 ]
echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
}
#
# Define a boolean to a specific value.
#
function define_bool () {
eval $1=$2
}
function define_tristate () {
eval $1=$2
}
function define_hex () {
eval $1=$2
}
function define_int () {
eval $1=$2
}
function define_string () {
eval $1=\"$2\"
}
#
# Create a boolean (Yes/No) function for our current menu
# which calls our local bool function.
#
function bool () {
set_x_info "$2" "n"
case $x in
y|m) flag="*" ;;
n) flag=" " ;;
esac
echo -ne "'$2' '[$flag] $1$info' " >>MCmenu
echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists
}
#
# Create a tristate (Yes/No/Module) radiolist function
# which calls our local tristate function.
#
# Collapses to a boolean (Yes/No) if module support is disabled.
#
function tristate () {
if [ "$CONFIG_MODULES" != "y" ]
then
bool "$1" "$2"
else
set_x_info "$2" "n"
case $x in
y) flag="*" ;;
m) flag="M" ;;
*) flag=" " ;;
esac
echo -ne "'$2' '<$flag> $1$info' " >>MCmenu
echo -e "
function $2 () { l_tristate '$2' \"\$1\" ;}" >>MCradiolists
fi
}
#
# Create a tristate radiolist function which is dependent on
# another kernel configuration option.
#
# Quote from the original configure script:
#
# If the option we depend upon is a module,
# then the only allowable options are M or N. If Y, then
# this is a normal tristate. This is used in cases where modules
# are nested, and one module requires the presence of something
# else in the kernel.
#
function dep_tristate () {
ques="$1"
var="$2"
dep=y
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y ]; then
shift
elif [ "$1" = m ]; then
dep=m
shift
else
dep=n
shift $#
fi
done
if [ "$dep" = y ]; then
tristate "$ques" "$var"
elif [ "$dep" = m ]; then
mod_bool "$ques" "$var"
else
define_tristate "$var" n
fi
}
#
# Same as above, but now only Y and N are allowed as dependency
# (i.e. third and next arguments).
#
function dep_bool () {
ques="$1"
var="$2"
dep=y
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y ]; then
shift
else
dep=n
shift $#
fi
done
if [ "$dep" = y ]; then
bool "$ques" "$var"
else
define_bool "$var" n
fi
}
function dep_mbool () {
ques="$1"
var="$2"
dep=y
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y -o "$1" = m ]; then
shift
else
dep=n
shift $#
fi
done
if [ "$dep" = y ]; then
bool "$ques" "$var"
else
define_bool "$var" n
fi
}
#
# Add a menu item which will call our local int function.
#
function int () {
set_x_info "$2" "$3"
echo -ne "'$2' '($x) $1$info' " >>MCmenu
echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
}
#
# Add a menu item which will call our local hex function.
#
function hex () {
set_x_info "$2" "$3"
x=${x##*[x,X]}
echo -ne "'$2' '($x) $1$info' " >>MCmenu
echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
}
#
# Add a menu item which will call our local string function.
#
function string () {
set_x_info "$2" "$3"
echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu
echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists
}
#
# Add a menu item which will call our local One-of-Many choice list.
#
function choice () {
#
# Need to remember params cause they're gonna get reset.
#
title=$1
choices=$2
default=$3
current=
#
# Find out if one of the choices is already set.
# If it's not then make it the default.
#
set -- $choices
firstchoice=$2
while [ -n "$2" ]
do
if eval [ \"_\$$2\" = \"_y\" ]
then
current=$1
break
fi
shift ; shift
done
: ${current:=$default}
echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
echo -e "
function $firstchoice () \
{ l_choice '$title' \"$choices\" \"$current\" ;}" >>MCradiolists
}
} # END load_functions()
#
# Extract available help for an option from Config.help
# and send it to standard output.
#
# Most of this function was borrowed from the original kernel
# Configure script.
#
function extract_help () {
#first escape regexp special characters in the argument:
var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
#now pick out the right help text:
text=$(cat /dev/null $(find . -name Config.help) |
sed -n "/^$var[ ]*\$/,\${
/^$var[ ]*\$/c\\
${var}:\\
/^#/b
/^[^ ]/q
s/^ //
/<file:\\([^>]*\\)>/s//\\1/g
p
}")
if [ -z "$text" ]
then
echo "There is no help available for this kernel option."
return 1
else
echo "$text"
fi
}
#
# Activate a help dialog.
#
function help () {
if extract_help $1 >help.out
then
$DIALOG --backtitle "$backtitle" --title "$2"\
--textbox help.out $ROWS $COLS
else
$DIALOG --backtitle "$backtitle" \
--textbox help.out $ROWS $COLS
fi
rm -f help.out
}
#
# Show the README file.
#
function show_readme () {
$DIALOG --backtitle "$backtitle" \
--textbox scripts/README.Menuconfig $ROWS $COLS
}
#
# Begin building the dialog menu command and Initialize the
# Radiolist function file.
#
function menu_name () {
echo -ne "$DIALOG --title '$1'\
--backtitle '$backtitle' \
--menu '$menu_instructions' \
$ROWS $COLS $((ROWS-10)) \
'$default' " >MCmenu
>MCradiolists
}
#
# Add a submenu option to the menu currently under construction.
#
function submenu () {
echo -ne "'activate_menu $2' '$1 --->' " >>MCmenu
}
#
# Handle a boolean (Yes/No) option.
#
function l_bool () {
if [ -n "$2" ]
then
case "$2" in
y|m) eval $1=y ;;
c) eval x=\$$1
case $x in
y) eval $1=n ;;
n) eval $1=y ;;
*) eval $1=y ;;
esac ;;
*) eval $1=n ;;
esac
else
echo -ne "\007"
fi
}
#
# Same as bool() except options are (Module/No)
#
function mod_bool () {
if [ "$CONFIG_MODULES" != "y" ]; then
define_bool "$2" "n"
else
set_x_info "$2" "n"
case $x in
y|m) flag='M' ;;
*) flag=' ' ;;
esac
echo -ne "'$2' '<$flag> $1$info' " >>MCmenu
echo -e "function $2 () { l_mod_bool '$2' \"\$1\" ;}" >>MCradiolists
fi
}
#
# Same as l_bool() except options are (Module/No)
#
function l_mod_bool() {
if [ -n "$2" ]
then
case "$2" in
y) echo -en "\007"
${DIALOG} --backtitle "$backtitle" \
--infobox "\
This feature depends on another which has been configured as a module. \
As a result, this feature will be built as a module." 4 70
sleep 5
eval $1=m ;;
m) eval $1=m ;;
c) eval x=\$$1
case $x in
m) eval $1=n ;;
n) eval $1=m ;;
*) eval $1=m ;;
esac ;;
*) eval $1=n ;;
esac
else
echo -ne "\007"
fi
}
#
# Handle a tristate (Yes/No/Module) option.
#
function l_tristate () {
if [ -n "$2" ]
then
eval x=\$$1
case "$2" in
y) eval $1=y ;;
m) eval $1=m ;;
c) eval x=\$$1
case $x in
y) eval $1=n ;;
n) eval $1=m ;;
m) eval $1=y ;;
*) eval $1=y ;;
esac ;;
*) eval $1=n ;;
esac
else
echo -ne "\007"
fi
}
#
# Create a dialog for entering an integer into a kernel option.
#
function l_int () {
while true
do
if $DIALOG --title "$1" \
--backtitle "$backtitle" \
--inputbox "$inputbox_instructions_int" \
10 75 "$4" 2>MCdialog.out
then
answer="`cat MCdialog.out`"
answer="${answer:-$3}"
# Semantics of + and ? in GNU expr changed, so
# we avoid them:
if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
then
eval $2=\"$answer\"
else
eval $2=\"$3\"
echo -en "\007"
${DIALOG} --backtitle "$backtitle" \
--infobox "You have made an invalid entry." 3 43
sleep 2
fi
break
fi
help "$2" "$1"
done
}
#
# Create a dialog for entering a hexadecimal into a kernel option.
#
function l_hex () {
while true
do
if $DIALOG --title "$1" \
--backtitle "$backtitle" \
--inputbox "$inputbox_instructions_hex" \
10 75 "$4" 2>MCdialog.out
then
answer="`cat MCdialog.out`"
answer="${answer:-$3}"
answer="${answer##*[x,X]}"
if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
then
eval $2=\"$answer\"
else
eval $2=\"$3\"
echo -en "\007"
${DIALOG} --backtitle "$backtitle" \
--infobox "You have made an invalid entry." 3 43
sleep 2
fi
break
fi
help "$2" "$1"
done
}
#
# Create a dialog for entering a string into a kernel option.
#
function l_string () {
while true
do
if $DIALOG --title "$1" \
--backtitle "$backtitle" \
--inputbox "$inputbox_instructions_string" \
10 75 "$4" 2>MCdialog.out
then
answer="`cat MCdialog.out`"
answer="${answer:-$3}"
#
# Someone may add a nice check for the entered
# string here...
#
eval $2=\"$answer\"
break
fi
help "$2" "$1"
done
}
#
# Handle a one-of-many choice list.
#
function l_choice () {
#
# Need to remember params cause they're gonna get reset.
#
title="$1"
choices="$2"
current="$3"
chosen=
#
# Scan current value of choices and set radiolist switches.
#
list=
set -- $choices
firstchoice=$2
while [ -n "$2" ]
do
case "$1" in
"$current"*) if [ -z "$chosen" ]; then
list="$list $2 $1 ON "
chosen=1
else
list="$list $2 $1 OFF "
fi ;;
*) list="$list $2 $1 OFF " ;;
esac
shift ; shift
done
while true
do
if $DIALOG --title "$title" \
--backtitle "$backtitle" \
--radiolist "$radiolist_instructions" \
15 70 6 $list 2>MCdialog.out
then
choice=`cat MCdialog.out`
break
fi
help "$firstchoice" "$title"
done
#
# Now set the boolean value of each option based on
# the selection made from the radiolist.
#
set -- $choices
while [ -n "$2" ]
do
if [ "$2" = "$choice" ]
then
eval $2=\"y\"
else
eval $2=\"n\"
fi
shift ; shift
done
}
#
# Call awk, and watch for error codes, etc.
#
function callawk () {
awk "$1" || { echo "Awk died with error code $?. Giving up."; exit 1; }
}
#
# A faster awk based recursive parser. (I hope)
#
function parser1 () {
callawk '
BEGIN {
menu_no = 0
comment_is_option = 0
parser("'$CONFIG_IN'","MCmenu0")
}
function parser(ifile,menu) {
while (getline <ifile) {
if ($1 == "mainmenu_option") {
comment_is_option = "1"
}
else if ($1 == "comment" && comment_is_option == "1") {
comment_is_option= "0"
sub($1,"",$0)
++menu_no
printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
newmenu = sprintf("MCmenu%d", menu_no);
printf( "function MCmenu%s () {\n"\
"default=$1\n"\
"menu_name %s\n",\
menu_no, $0) >newmenu
parser(ifile, newmenu)
}
else if ($0 ~ /^#|\$MAKE|mainmenu_name/) {
printf("") >>menu
}
else if ($1 ~ "endmenu") {
printf("}\n") >>menu
return
}
else if ($1 == "source") {
parser($2,menu)
}
else {
print >>menu
}
}
}'
}
#
# Secondary parser for single menu mode.
#
function parser2 () {
callawk '
BEGIN {
parser("'$CONFIG_IN'","MCmenu0")
}
function parser(ifile,menu) {
while (getline <ifile) {
if ($0 ~ /^#|$MAKE|mainmenu_name/) {
printf("") >>menu
}
else if ($1 ~ /mainmenu_option|endmenu/) {
printf("") >>menu
}
else if ($1 == "source") {
parser($2,menu)
}
else {
print >>menu
}
}
}'
}
#
# Parse all the config.in files into mini scripts.
#
function parse_config_files () {
rm -f MCmenu*
echo "function MCmenu0 () {" >MCmenu0
echo 'default=$1' >>MCmenu0
echo "menu_name 'Main Menu'" >>MCmenu0
if [ "_$single_menu_mode" = "_TRUE" ]
then
parser2
else
parser1
fi
echo "comment ''" >>MCmenu0
echo "g_alt_config" >>MCmenu0
echo "s_alt_config" >>MCmenu0
echo "}" >>MCmenu0
#
# These mini scripts must be sourced into the current
# environment in order for all of this to work. Leaving
# them on the disk as executables screws up the recursion
# in activate_menu(), among other things. Once they are
# sourced we can discard them.
#
for i in MCmenu*
do
echo -n "."
source ./$i
done
rm -f MCmenu*
}
#
# This is the menu tree's bootstrap.
#
# Executes the parsed menus on demand and creates a set of functions,
# one per configuration option. These functions will in turn execute
# dialog commands or recursively call other menus.
#
function activate_menu () {
rm -f lxdialog.scrltmp
while true
do
comment_ctr=0 #So comment lines get unique tags
$1 "$default" 2> MCerror #Create the lxdialog menu & functions
if [ "$?" != "0" ]
then
clear
cat <<EOM
Menuconfig has encountered a possible error in one of the kernel's
configuration files and is unable to continue. Here is the error
report:
EOM
sed 's/^/ Q> /' MCerror
cat <<EOM
Please report this to the maintainer <mec@shout.net>. You may also
send a problem report to <linux-kernel@vger.kernel.org>.
Please indicate the kernel version you are trying to configure and
which menu you were trying to enter when this error occurred.
EOM
cleanup
exit 1
fi
rm -f MCerror
. ./MCradiolists #Source the menu's functions
. ./MCmenu 2>MCdialog.out #Activate the lxdialog menu
ret=$?
read selection <MCdialog.out
case "$ret" in
0|3|4|5|6)
defaults="$selection$defaults" #pseudo stack
case "$ret" in
0) eval $selection ;;
3) eval $selection y ;;
4) eval $selection n ;;
5) eval $selection m ;;
6) eval $selection c ;;
esac
default="${defaults%%*}" defaults="${defaults#*}"
;;
2)
default="${selection%%\ *}"
case "$selection" in
*"-->"*|*"alt_config"*)
show_readme ;;
*)
eval help $selection ;;
esac
;;
255|1)
break
;;
139)
stty sane
clear
cat <<EOM
There seems to be a problem with the lxdialog companion utility which is
built prior to running Menuconfig. Usually this is an indicator that you
have upgraded/downgraded your ncurses libraries and did not remove the
old ncurses header file(s) in /usr/include or /usr/include/ncurses.
It is VERY important that you have only one set of ncurses header files
and that those files are properly version matched to the ncurses libraries
installed on your machine.
You may also need to rebuild lxdialog. This can be done by moving to
the /usr/src/linux/scripts/lxdialog directory and issuing the
"make clean all" command.
If you have verified that your ncurses install is correct, you may email
the maintainer <mec@shout.net> or post a message to
<linux-kernel@vger.kernel.org> for additional assistance.
EOM
cleanup
exit 139
;;
esac
done
}
#
# Create a menu item to load an alternate configuration file.
#
g_alt_config () {
echo -n "get_alt_config 'Load an Alternate Configuration File' "\
>>MCmenu
}
#
# Get alternate config file name and load the
# configuration from it.
#
get_alt_config () {
set -f ## Switch file expansion OFF
while true
do
ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}"
$DIALOG --backtitle "$backtitle" \
--inputbox "\
Enter the name of the configuration file you wish to load. \
Accept the name shown to restore the configuration you \
last retrieved. Leave blank to abort."\
11 55 "$ALT_CONFIG" 2>MCdialog.out
if [ "$?" = "0" ]
then
ALT_CONFIG=`cat MCdialog.out`
[ "_" = "_$ALT_CONFIG" ] && break
if eval [ -r \"$ALT_CONFIG\" ]
then
eval load_config_file \"$ALT_CONFIG\"
break
else
echo -ne "\007"
$DIALOG --backtitle "$backtitle" \
--infobox "File does not exist!" 3 38
sleep 2
fi
else
cat <<EOM >help.out
For various reasons, one may wish to keep several different kernel
configurations available on a single machine.
If you have saved a previous configuration in a file other than the
kernel's default, entering the name of the file here will allow you
to modify that configuration.
If you are uncertain, then you have probably never used alternate
configuration files. You should therefor leave this blank to abort.
EOM
$DIALOG --backtitle "$backtitle"\
--title "Load Alternate Configuration"\
--textbox help.out $ROWS $COLS
fi
done
set +f ## Switch file expansion ON
rm -f help.out MCdialog.out
}
#
# Create a menu item to store an alternate config file.
#
s_alt_config () {
echo -n "save_alt_config 'Save Configuration to an Alternate File' "\
>>MCmenu
}
#
# Get an alternate config file name and save the current
# configuration to it.
#
save_alt_config () {
set -f ## Switch file expansion OFF
while true
do
$DIALOG --backtitle "$backtitle" \
--inputbox "\
Enter a filename to which this configuration should be saved \
as an alternate. Leave blank to abort."\
10 55 "$ALT_CONFIG" 2>MCdialog.out
if [ "$?" = "0" ]
then
ALT_CONFIG=`cat MCdialog.out`
[ "_" = "_$ALT_CONFIG" ] && break
if eval touch $ALT_CONFIG 2>/dev/null
then
eval save_configuration $ALT_CONFIG
load_functions ## RELOAD
break
else
echo -ne "\007"
$DIALOG --backtitle "$backtitle" \
--infobox "Can't create file! Probably a nonexistent directory." 3 60
sleep 2
fi
else
cat <<EOM >help.out
For various reasons, one may wish to keep different kernel
configurations available on a single machine.
Entering a file name here will allow you to later retrieve, modify
and use the current configuration as an alternate to whatever
configuration options you have selected at that time.
If you are uncertain what all this means then you should probably
leave this blank.
EOM
$DIALOG --backtitle "$backtitle"\
--title "Save Alternate Configuration"\
--textbox help.out $ROWS $COLS
fi
done
set +f ## Switch file expansion ON
rm -f help.out MCdialog.out
}
#
# Load config options from a file.
# Converts all "# OPTION is not set" lines to "OPTION=n" lines
#
function load_config_file () {
awk '
/# .* is not set.*/ { printf("%s=n\n", $2) }
! /# .* is not set.*/ { print }
' $1 >.tmpconfig
source ./.tmpconfig
rm -f .tmpconfig
}
#
# Just what it says.
#
save_configuration () {
echo
echo -n "Saving your kernel configuration."
#
# Now, let's redefine the configuration functions for final
# output to the config files.
#
# Nested function definitions, YIPEE!
#
function bool () {
set_x_info "$2" "n"
eval define_bool \"$2\" \"$x\"
}
function tristate () {
set_x_info "$2" "n"
eval define_tristate \"$2\" \"$x\"
}
function dep_tristate () {
set_x_info "$2" "n"
var="$2"
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y ]; then
shift
elif [ "$1" = m -a "$x" != n ]; then
x=m; shift
else
x=n; shift $#
fi
done
define_tristate "$var" "$x"
}
function dep_bool () {
set_x_info "$2" "n"
var="$2"
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y ]; then
shift
else
x=n; shift $#
fi
done
define_bool "$var" "$x"
}
function dep_mbool () {
set_x_info "$2" "n"
var="$2"
shift 2
while [ $# -gt 0 ]; do
if [ "$1" = y -o "$1" = m ]; then
shift
else
x=n; shift $#
fi
done
define_bool "$var" "$x"
}
function int () {
set_x_info "$2" "$3"
echo "$2=$x" >>$CONFIG
echo "#define $2 ($x)" >>$CONFIG_H
}
function hex () {
set_x_info "$2" "$3"
echo "$2=$x" >>$CONFIG
echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
}
function string () {
set_x_info "$2" "$3"
echo "$2=\"$x\"" >>$CONFIG
echo "#define $2 \"$x\"" >>$CONFIG_H
}
function define_hex () {
eval $1=\"$2\"
echo "$1=$2" >>$CONFIG
echo "#define $1 0x${2##*[x,X]}" >>$CONFIG_H
}
function define_int () {
eval $1=\"$2\"
echo "$1=$2" >>$CONFIG
echo "#define $1 ($2)" >>$CONFIG_H
}
function define_string () {
eval $1=\"$2\"
echo "$1=\"$2\"" >>$CONFIG
echo "#define $1 \"$2\"" >>$CONFIG_H
}
function define_bool () {
define_tristate "$1" "$2"
}
function define_tristate () {
eval $1=\"$2\"
case "$2" in
y)
echo "$1=y" >>$CONFIG
echo "#define $1 1" >>$CONFIG_H
;;
m)
if [ "$CONFIG_MODULES" = "y" ]
then
echo "$1=m" >>$CONFIG
echo "#undef $1" >>$CONFIG_H
echo "#define $1_MODULE 1" >>$CONFIG_H
else
echo "$1=y" >>$CONFIG
echo "#define $1 1" >>$CONFIG_H
fi
;;
n)
echo "# $1 is not set" >>$CONFIG
echo "#undef $1" >>$CONFIG_H
;;
esac
}
function choice () {
#
# Find the first choice that's already set to 'y'
#
choices="$2"
default="$3"
current=
chosen=
set -- $choices
while [ -n "$2" ]
do
if eval [ \"_\$$2\" = \"_y\" ]
then
current=$1
break
fi
shift ; shift
done
#
# Use the default if none were set.
#
: ${current:=$default}
#
# Output all choices (to be compatible with other configs).
#
set -- $choices
while [ -n "$2" ]
do
case "$1" in
"$current"*) if [ -z "$chosen" ]; then
define_bool "$2" "y"
chosen=1
else
define_bool "$2" "n"
fi ;;
*) define_bool "$2" "n" ;;
esac
shift ; shift
done
}
function mainmenu_name () {
:
}
function mainmenu_option () {
comment_is_option=TRUE
}
function endmenu () {
:
}
function comment () {
if [ "$comment_is_option" ]
then
comment_is_option=
echo >>$CONFIG
echo "#" >>$CONFIG
echo "# $1" >>$CONFIG
echo "#" >>$CONFIG
echo >>$CONFIG_H
echo "/*" >>$CONFIG_H
echo " * $1" >>$CONFIG_H
echo " */" >>$CONFIG_H
fi
}
echo -n "."
DEF_CONFIG="${1:-.config}"
DEF_CONFIG_H="include/linux/autoconf.h"
CONFIG=.tmpconfig
CONFIG_H=.tmpconfig.h
echo "#" >$CONFIG
echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG
echo "#" >>$CONFIG
echo "/*" >$CONFIG_H
echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
echo " */" >>$CONFIG_H
echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
echo -n "."
if . $CONFIG_IN >>.menuconfig.log 2>&1
then
if [ "$DEF_CONFIG" = ".config" ]
then
mv $CONFIG_H $DEF_CONFIG_H
fi
if [ -f "$DEF_CONFIG" ]
then
rm -f ${DEF_CONFIG}.old
mv $DEF_CONFIG ${DEF_CONFIG}.old
fi
mv $CONFIG $DEF_CONFIG
return 0
else
return 1
fi
}
#
# Remove temporary files
#
cleanup () {
cleanup1
cleanup2
}
cleanup1 () {
rm -f MCmenu* MCradiolists MCdialog.out help.out
}
cleanup2 () {
rm -f .tmpconfig .tmpconfig.h
}
set_geometry () {
# Some distributions export these with incorrect values
# which can really screw up some ncurses programs.
LINES= COLUMNS=
ROWS=${1:-24} COLS=${2:-80}
# Just in case the nasty rlogin bug returns.
#
[ $ROWS = 0 ] && ROWS=24
[ $COLS = 0 ] && COLS=80
if [ $ROWS -lt 19 -o $COLS -lt 80 ]
then
echo -e "\n\007Your display is too small to run Menuconfig!"
echo "It must be at least 19 lines by 80 columns."
exit 1
fi
ROWS=$((ROWS-4)) COLS=$((COLS-5))
}
set_geometry `stty size 2>/dev/null`
menu_instructions="\
Arrow keys navigate the menu. \
<Enter> selects submenus --->. \
Highlighted letters are hotkeys. \
Pressing <Y> includes, <N> excludes, <M> modularizes features. \
Press <Esc><Esc> to exit, <?> for Help. \
Legend: [*] built-in [ ] excluded <M> module < > module capable"
radiolist_instructions="\
Use the arrow keys to navigate this window or \
press the hotkey of the item you wish to select \
followed by the <SPACE BAR>.
Press <?> for additional information about this option."
inputbox_instructions_int="\
Please enter a decimal value. \
Fractions will not be accepted. \
Use the <TAB> key to move from the input field to the buttons below it."
inputbox_instructions_hex="\
Please enter a hexadecimal value. \
Use the <TAB> key to move from the input field to the buttons below it."
inputbox_instructions_string="\
Please enter a string value. \
Use the <TAB> key to move from the input field to the buttons below it."
DIALOG="./scripts/lxdialog/lxdialog"
kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
backtitle="Linux Kernel v$kernel_version Configuration"
trap "cleanup ; exit 1" 1 2 15
#
# Locate default files.
#
CONFIG_IN=./config.in
if [ "$1" != "" ] ; then
CONFIG_IN=$1
fi
DEFAULTS=arch/$ARCH/defconfig
if [ -f .config ]; then
DEFAULTS=.config
fi
if [ -f $DEFAULTS ]
then
echo "Using defaults found in" $DEFAULTS
load_config_file $DEFAULTS
else
echo "No defaults found"
fi
# Fresh new log.
>.menuconfig.log
# Load the functions used by the config.in files.
echo -n "Preparing scripts: functions"
load_functions
if [ ! -e $CONFIG_IN ]
then
echo "Your main config.in file ($CONFIG_IN) does not exist"
exit 1
fi
if [ ! -x $DIALOG ]
then
echo "Your lxdialog utility does not exist"
exit 1
fi
#
# Read config.in files and parse them into one shell function per menu.
#
echo -n ", parsing"
parse_config_files $CONFIG_IN
echo "done."
#
# Start the ball rolling from the top.
#
activate_menu MCmenu0
#
# All done!
#
cleanup1
#
# Confirm and Save
#
if $DIALOG --backtitle "$backtitle" \
--yesno "Do you wish to save your new kernel configuration?" 5 60
then
save_configuration
echo
echo
echo "*** End of Linux kernel configuration."
echo "*** Check the top-level Makefile for additional configuration."
if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then
echo "*** Next, you must run 'make dep'."
else
echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'."
fi
echo
else
echo
echo
echo Your kernel configuration changes were NOT saved.
echo
fi
# Remove log if empty.
if [ ! -s .menuconfig.log ] ; then
rm -f .menuconfig.log
fi
exit 0
# FILE: tail.tk
# This file is boilerplate TCL/TK function definitions for 'make xconfig'.
#
# CHANGES
# =======
#
# 8 January 1998, Michael Elizabeth Chastain, <mec@shout.net>
# Arrange buttons in three columns for better screen fitting.
#
#
# Read the user's settings from .config. These will override whatever is
# in config.in. Don't do this if the user specified a -D to force
# the defaults.
#
if { [file readable .config] == 1} then {
if { $argc > 0 } then {
if { [lindex $argv 0] != "-D" } then {
read_config .config
}
else
{
read_config $defaults
}
} else {
read_config .config
}
} else {
read_config $defaults
}
update_define 1 $total_menus 0
update_mainmenu
button .f0.right.save -anchor w -text "Save and Exit" -underline 0\
-command { catch {exec cp -f .config .config.old}; \
writeconfig .config include/linux/autoconf.h; wrapup .wrap }
button .f0.right.quit -anchor w -text "Quit Without Saving" -underline 0\
-command { maybe_exit .maybe }
button .f0.right.load -anchor w -text "Load Configuration from File" \
-command { load_configfile .load "Load Configuration from file" read_config_file
}
button .f0.right.store -anchor w -text "Store Configuration to File" \
-command { load_configfile .load "Store Configuration to file" write_config_file }
#
# Now pack everything.
#
pack .f0.right.store .f0.right.load .f0.right.quit .f0.right.save \
-padx 0 -pady 0 -side bottom -fill x
pack .f0.left .f0.middle .f0.right -side left -padx 5 -pady 0 -fill y
pack .f0 -padx 5 -pady 5
update idletasks
set winy [expr 10 + [winfo reqheight .f0]]
set scry [lindex [wm maxsize .] 1]
set winx [expr 10 + [winfo reqwidth .f0]]
set scrx [lindex [wm maxsize .] 0]
if {$winx < $scrx} then {set maxx -1} else {set maxx $winx}
if {$winy < $scry} then {set maxy -1} else {set maxy $winy}
.f0 configure -width $winx -height $winy
wm maxsize . $maxx $maxy
#
# If we cannot write our config files, disable the write button.
#
if { [file exists .config] == 1 } then {
if { [file writable .config] == 0 } then {
.f0.right.save configure -state disabled
}
} else {
if { [file writable .] == 0 } then {
.f0.right.save configure -state disabled
}
}
if { [file exists include/linux/autoconf.h] == 1 } then {
if { [file writable include/linux/autoconf.h] == 0 } then {
.f0.right.save configure -state disabled
}
} else {
if { [file writable include/linux/] == 0 } then {
.f0.right.save configure -state disabled
}
}
/*
* tkcond.c
*
* Eric Youngdale was the original author of xconfig.
* Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
*
* This file takes the tokenized statement list and transforms 'if ...'
* statements. For each simple statement, I find all of the 'if' statements
* that enclose it, and attach the aggregate conditionals of those 'if'
* statements to the cond list of the simple statement.
*
* 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
* - Steam-clean this file. I tested this by generating kconfig.tk for
* every architecture and comparing it character-for-character against
* the output of the old tkparse.
*
* 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
* - kvariables removed; all variables are stored in a single table now
* - some elimination of options non-valid for current architecture
* implemented.
* - negation (!) eliminated from conditions
*
* TO DO:
* - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
* you are interested in working on the replacement.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tkparse.h"
/*
* Mark variables which are defined anywhere.
*/
static void mark_variables( struct kconfig * scfg )
{
struct kconfig * cfg;
int i;
for ( i = 1; i <= max_varnum; i++ )
vartable[i].defined = 0;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
if ( cfg->token == token_bool
|| cfg->token == token_choice_item
|| cfg->token == token_define_bool
|| cfg->token == token_define_hex
|| cfg->token == token_define_int
|| cfg->token == token_define_string
|| cfg->token == token_define_tristate
|| cfg->token == token_dep_bool
|| cfg->token == token_dep_mbool
|| cfg->token == token_dep_tristate
|| cfg->token == token_hex
|| cfg->token == token_int
|| cfg->token == token_string
|| cfg->token == token_tristate
|| cfg->token == token_unset )
{
if ( cfg->nameindex > 0 ) /* paranoid */
{
vartable[cfg->nameindex].defined = 1;
}
}
}
}
static void free_cond( struct condition *cond )
{
struct condition *tmp, *tmp1;
for ( tmp = cond; tmp; tmp = tmp1 )
{
tmp1 = tmp->next;
free( (void*)tmp );
}
}
/*
* Remove the bang operator from a condition to avoid priority problems.
* "!" has different priorities as "test" command argument and in
* a tk script.
*/
static struct condition * remove_bang( struct condition * condition )
{
struct condition * conda, * condb, * prev = NULL;
for ( conda = condition; conda; conda = conda->next )
{
if ( conda->op == op_bang && conda->next &&
( condb = conda->next->next ) )
{
if ( condb->op == op_eq || condb->op == op_neq )
{
condb->op = (condb->op == op_eq) ? op_neq : op_eq;
conda->op = op_nuked;
if ( prev )
{
prev->next = conda->next;
}
else
{
condition = conda->next;
}
conda->next = NULL;
free_cond( conda );
conda = condb;
}
}
prev = conda;
}
return condition;
}
/*
* Make a new condition chain by joining the current condition stack with
* the "&&" operator for glue.
*/
static struct condition * join_condition_stack( struct condition * conditions [],
int depth )
{
struct condition * cond_list;
struct condition * cond_last;
int i, is_first = 1;
cond_list = cond_last = NULL;
for ( i = 0; i < depth; i++ )
{
if ( conditions[i]->op == op_false )
{
struct condition * cnew;
/* It is always false condition */
cnew = malloc( sizeof(*cnew) );
memset( cnew, 0, sizeof(*cnew) );
cnew->op = op_false;
cond_list = cond_last = cnew;
goto join_done;
}
}
for ( i = 0; i < depth; i++ )
{
struct condition * cond;
struct condition * cnew;
int add_paren;
/* omit always true conditions */
if ( conditions[i]->op == op_true )
continue;
/* if i have another condition, add an '&&' operator */
if ( !is_first )
{
cnew = malloc( sizeof(*cnew) );
memset( cnew, 0, sizeof(*cnew) );
cnew->op = op_and;
cond_last->next = cnew;
cond_last = cnew;
}
if ( conditions[i]->op != op_lparen )
{
/* add a '(' */
add_paren = 1;
cnew = malloc( sizeof(*cnew) );
memset( cnew, 0, sizeof(*cnew) );
cnew->op = op_lparen;
if ( cond_last == NULL )
{ cond_list = cond_last = cnew; }
else
{ cond_last->next = cnew; cond_last = cnew; }
}
else
{
add_paren = 0;
}
/* duplicate the chain */
for ( cond = conditions [i]; cond != NULL; cond = cond->next )
{
cnew = malloc( sizeof(*cnew) );
cnew->next = NULL;
cnew->op = cond->op;
cnew->str = cond->str ? strdup( cond->str ) : NULL;
cnew->nameindex = cond->nameindex;
if ( cond_last == NULL )
{ cond_list = cond_last = cnew; }
else
{ cond_last->next = cnew; cond_last = cnew; }
}
if ( add_paren )
{
/* add a ')' */
cnew = malloc( sizeof(*cnew) );
memset( cnew, 0, sizeof(*cnew) );
cnew->op = op_rparen;
cond_last->next = cnew;
cond_last = cnew;
}
is_first = 0;
}
/*
* Remove duplicate conditions.
*/
{
struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
{
if ( cond1->op == op_lparen )
{
cond1b = cond1 ->next; if ( cond1b == NULL ) break;
cond1c = cond1b->next; if ( cond1c == NULL ) break;
cond1d = cond1c->next; if ( cond1d == NULL ) break;
cond1e = cond1d->next; if ( cond1e == NULL ) break;
cond1f = cond1e->next; if ( cond1f == NULL ) break;
if ( cond1b->op == op_variable
&& ( cond1c->op == op_eq || cond1c->op == op_neq )
&& cond1d->op == op_constant
&& cond1e->op == op_rparen )
{
struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
{
if ( cond2->op == op_lparen )
{
cond2b = cond2 ->next; if ( cond2b == NULL ) break;
cond2c = cond2b->next; if ( cond2c == NULL ) break;
cond2d = cond2c->next; if ( cond2d == NULL ) break;
cond2e = cond2d->next; if ( cond2e == NULL ) break;
cond2f = cond2e->next;
/* look for match */
if ( cond2b->op == op_variable
&& cond2b->nameindex == cond1b->nameindex
&& cond2c->op == cond1c->op
&& cond2d->op == op_constant
&& strcmp( cond2d->str, cond1d->str ) == 0
&& cond2e->op == op_rparen )
{
/* one of these must be followed by && */
if ( cond1f->op == op_and
|| ( cond2f != NULL && cond2f->op == op_and ) )
{
/* nuke the first duplicate */
cond1 ->op = op_nuked;
cond1b->op = op_nuked;
cond1c->op = op_nuked;
cond1d->op = op_nuked;
cond1e->op = op_nuked;
if ( cond1f->op == op_and )
cond1f->op = op_nuked;
else
cond2f->op = op_nuked;
}
}
}
}
}
}
}
}
join_done:
return cond_list;
}
static char * current_arch = NULL;
/*
* Eliminating conditions with ARCH = <not current>.
*/
static struct condition *eliminate_other_arch( struct condition *list )
{
struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL;
if ( current_arch == NULL )
current_arch = getenv( "ARCH" );
if ( current_arch == NULL )
{
fprintf( stderr, "error: ARCH undefined\n" );
exit( 1 );
}
if ( cond1a->op == op_variable
&& ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
{
cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
cond1d = cond1c->next;
if ( cond1c->op == op_constant && cond1d == NULL )
{
if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for another architecture */
cond1a->op = op_false;
cond1a->next = NULL;
free_cond( cond1b );
return cond1a;
}
else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for current architecture */
cond1a->op = op_true;
cond1a->next = NULL;
free_cond( cond1b );
return cond1a;
}
}
else if ( cond1c->op == op_constant && cond1d->op == op_or )
{
if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for another architecture */
cond1b = cond1d->next;
cond1d->next = NULL;
free_cond( cond1a );
return eliminate_other_arch( cond1b );
}
else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for current architecture */
cond1a->op = op_true;
cond1a->next = NULL;
free_cond( cond1b );
return cond1a;
}
}
else if ( cond1c->op == op_constant && cond1d->op == op_and )
{
if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for another architecture */
int l_par = 0;
for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
{
if ( cond1c->op == op_lparen )
l_par++;
else if ( cond1c->op == op_rparen )
l_par--;
else if ( cond1c->op == op_or && l_par == 0 )
/* Expression too complex - don't touch */
return cond1a;
else if ( l_par < 0 )
{
fprintf( stderr, "incorrect condition: programming error ?\n" );
exit( 1 );
}
}
cond1a->op = op_false;
cond1a->next = NULL;
free_cond( cond1b );
return cond1a;
}
else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
|| (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
{
/* This is for current architecture */
cond1b = cond1d->next;
cond1d->next = NULL;
free_cond( cond1a );
return eliminate_other_arch( cond1b );
}
}
}
if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
{
cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
cond1d = cond1c->next;
if ( cond1c->op == op_constant
&& ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
{
if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
{
cond1a->op = op_false;
cond1a->next = NULL;
free_cond( cond1b );
return cond1a;
}
}
else if ( cond1c->op == op_constant && cond1d->op == op_or )
{
if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
{
cond1b = cond1d->next;
cond1d->next = NULL;
free_cond( cond1a );
return eliminate_other_arch( cond1b );
}
}
}
done:
return list;
}
/*
* This is the main transformation function.
*/
void fix_conditionals( struct kconfig * scfg )
{
struct kconfig * cfg;
/*
* Transform op_variable to op_kvariable.
*/
mark_variables( scfg );
/*
* Walk the statement list, maintaining a stack of current conditions.
* token_if push its condition onto the stack.
* token_else invert the condition on the top of the stack.
* token_endif pop the stack.
*
* For a simple statement, create a condition chain by joining together
* all of the conditions on the stack.
*/
{
struct condition * cond_stack [32];
int depth = 0;
struct kconfig * prev = NULL;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
int good = 1;
switch ( cfg->token )
{
default:
break;
case token_if:
cond_stack [depth++] =
remove_bang( eliminate_other_arch( cfg->cond ) );
cfg->cond = NULL;
break;
case token_else:
{
/*
* Invert the condition chain.
*
* Be careful to transfrom op_or to op_and1, not op_and.
* I will need this later in the code that removes
* duplicate conditions.
*/
struct condition * cond;
for ( cond = cond_stack [depth-1];
cond != NULL;
cond = cond->next )
{
switch( cond->op )
{
default: break;
case op_and: cond->op = op_or; break;
case op_or: cond->op = op_and1; break;
case op_neq: cond->op = op_eq; break;
case op_eq: cond->op = op_neq; break;
case op_true: cond->op = op_false;break;
case op_false:cond->op = op_true; break;
}
}
}
break;
case token_fi:
--depth;
break;
case token_bool:
case token_choice_item:
case token_choice_header:
case token_comment:
case token_define_bool:
case token_define_hex:
case token_define_int:
case token_define_string:
case token_define_tristate:
case token_endmenu:
case token_hex:
case token_int:
case token_mainmenu_option:
case token_string:
case token_tristate:
case token_unset:
cfg->cond = join_condition_stack( cond_stack, depth );
if ( cfg->cond && cfg->cond->op == op_false )
{
good = 0;
if ( prev )
prev->next = cfg->next;
else
scfg = cfg->next;
}
break;
case token_dep_bool:
case token_dep_mbool:
case token_dep_tristate:
/*
* Same as the other simple statements, plus an additional
* condition for the dependency.
*/
if ( cfg->cond )
{
cond_stack [depth] = eliminate_other_arch( cfg->cond );
cfg->cond = join_condition_stack( cond_stack, depth+1 );
}
else
{
cfg->cond = join_condition_stack( cond_stack, depth );
}
if ( cfg->cond && cfg->cond->op == op_false )
{
good = 0;
if ( prev )
prev->next = cfg->next;
else
scfg = cfg->next;
}
break;
}
if ( good )
prev = cfg;
}
}
}
#if 0
void dump_condition( struct condition *list )
{
struct condition *tmp;
for ( tmp = list; tmp; tmp = tmp->next )
{
switch (tmp->op)
{
default:
break;
case op_variable:
printf( " %s", vartable[tmp->nameindex].name );
break;
case op_constant:
printf( " %s", tmp->str );
break;
case op_eq:
printf( " =" );
break;
case op_bang:
printf( " !" );
break;
case op_neq:
printf( " !=" );
break;
case op_and:
case op_and1:
printf( " -a" );
break;
case op_or:
printf( " -o" );
break;
case op_true:
printf( " TRUE" );
break;
case op_false:
printf( " FALSE" );
break;
case op_lparen:
printf( " (" );
break;
case op_rparen:
printf( " )" );
break;
}
}
printf( "\n" );
}
#endif
/* Generate tk script based upon config.in
*
* Version 1.0
* Eric Youngdale
* 10/95
*
* 1996 01 04
* Avery Pennarun - Aesthetic improvements.
*
* 1996 01 24
* Avery Pennarun - Bugfixes and more aesthetics.
*
* 1996 03 08
* Avery Pennarun - The int and hex config.in commands work right.
* - Choice buttons are more user-friendly.
* - Disabling a text entry line greys it out properly.
* - dep_tristate now works like in Configure. (not pretty)
* - No warnings in gcc -Wall. (Fixed some "interesting" bugs.)
* - Faster/prettier "Help" lookups.
*
* 1996 03 15
* Avery Pennarun - Added new sed script from Axel Boldt to make help even
* faster. (Actually awk is downright slow on some machines.)
* - Fixed a bug I introduced into Choice dependencies. Thanks
* to Robert Krawitz for pointing this out.
*
* 1996 03 16
* Avery Pennarun - basic "do_make" support added to let sound config work.
*
* 1996 03 25
* Axel Boldt - Help now works on "choice" buttons.
*
* 1996 04 06
* Avery Pennarun - Improved sound config stuff. (I think it actually works
* now!)
* - Window-resize-limits don't use ugly /usr/lib/tk4.0 hack.
* - int/hex work with tk3 again. (The "cget" error.)
* - Next/Prev buttons switch between menus. I can't take
* much credit for this; the code was already there, but
* ifdef'd out for some reason. It flickers a lot, but
* I suspect there's no "easy" fix for that.
* - Labels no longer highlight as you move the mouse over
* them (although you can still press them... oh well.)
* - Got rid of the last of the literal color settings, to
* help out people with mono X-Windows systems.
* (Apparently there still are some out there!)
* - Tabstops seem sensible now.
*
* 1996 04 14
* Avery Pennarun - Reduced flicker when creating windows, even with "update
* idletasks" hack.
*
* 1997 12 08
* Michael Chastain - Remove sound driver special cases.
*
* 1997 11 15
* Michael Chastain - For choice buttons, write values for all options,
* not just the single chosen one. This is compatible
* with 'make config' and 'make oldconfig', and is
* needed so smart-config dependencies work if the
* user switches from one configuration method to
* another.
*
* 1998 03 09
* Axel Boldt - Smaller layout of main menu - it's still too big for 800x600.
* - Display help in text window to allow for cut and paste.
* - Allow for empty lines in help texts.
* - update_define should not set all variables unconditionally to
* 0: they may have been set to 1 elsewhere. CONFIG_NETLINK is
* an example.
*
* 1999 01 04
* Michael Elizabeth Chastain <mec@shout.net>
* - Call clear_globalflags when writing out update_mainmenu.
* This fixes the missing global/vfix lines for ARCH=alpha on 2.2.0-pre4.
*
* 8 January 1999, Michael Elizabeth Chastain <mec@shout.net>
* - Emit menus_per_column
*
* 14 January 1999, Michael Elizabeth Chastain <mec@shout.net>
* - Steam-clean this file. I tested this by generating kconfig.tk for every
* architecture and comparing it character-for-character against the output
* of the old tkparse.
* - Fix flattening of nested menus. The old code simply assigned items to
* the most recent token_mainmenu_option, without paying attention to scope.
* For example: "menu-1 bool-a menu-2 bool-b endmenu bool-c bool-d endmenu".
* The old code would put bool-a in menu-1, bool-b in menu-2, and bool-c
* and bool-d in *menu-2*. This hosed the nested submenus in
* drives/net/Config.in and other places.
* - Fix menu line wraparound at 128 menus (some fool used a 'char' for
* a counter).
*
* 23 January 1999, Michael Elizabeth Chastain <mec@shout.net>
* - Remove bug-compatible code.
*
* 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
* Some bugfixes, including
* - disabling "m" options when CONFIG_MODULES is set to "n" as well as "y"
* option in dep_tristate when dependency is set to "m",
* - deactivating choices which should not be available,
* - basic validation for int and hex introduced if the entered one is not
* valid,
* - updates of all opened menus instead of the active only. I was afraid
* that it would slow down updates, but I don't even see any speed difference
* on my machine. If it slows you can still work with only a single menu
* opened,
* - fixed error when focussing non-existent window (especially Help windows),
* Higher level submenus implemented.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "tkparse.h"
/*
* Total number of menus.
*/
static int tot_menu_num = 0;
/*
* Pointers to mainmenu_option and endmenu of each menu.
*/
struct kconfig * menu_first [100];
struct kconfig * menu_last [100];
/*
* Generate portion of wish script for the beginning of a submenu.
* The guts get filled in with the various options.
*/
static void start_proc( char * label, int menu_num, int toplevel )
{
if ( toplevel )
printf( "menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label );
printf( "proc menu%d {w title} {\n", menu_num );
printf( "\tset oldFocus [focus]\n" );
if ( menu_first[menu_num]->menu_number != 0 )
printf( "\tcatch {focus .menu%d}\n",
menu_first[menu_num]->menu_number );
printf( "\tcatch {destroy $w; unregister_active %d}\n", menu_num );
printf( "\ttoplevel $w -class Dialog\n" );
printf( "\twm withdraw $w\n" );
printf( "\tglobal active_menus\n" );
printf( "\tset active_menus [lsort -integer [linsert $active_menus end %d]]\n", menu_num );
printf( "\tmessage $w.m -width 400 -aspect 300 -text \\\n" );
printf( "\t\t\"%s\" -relief raised\n", label );
printf( "\tpack $w.m -pady 10 -side top -padx 10\n" );
printf( "\twm title $w \"%s\" \n\n", label );
printf( "\tbind $w <Escape> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; break\"\n", menu_num);
printf("\tset nextscript ");
printf("\"catch {focus $oldFocus}; " );
/*
* We are checking which windows should be destroyed and which are
* common parents with the next one. Remember that menu_num field
* in mainmenu_option record reports number of its *parent* menu.
*/
if ( menu_num < tot_menu_num
&& menu_first[menu_num + 1]->menu_number != menu_num )
{
int to_destr;
printf( "destroy $w; unregister_active %d; ", menu_num );
to_destr = menu_first[menu_num]->menu_number;
while ( to_destr > 0 && menu_first[menu_num + 1]->menu_number != to_destr )
{
printf( "catch {destroy .menu%d}; unregister_active %d; ",
to_destr, to_destr );
to_destr = menu_first[to_destr]->menu_number;
}
}
printf( "menu%d .menu%d \\\"$title\\\"\"\n",
menu_num+1, menu_num+1 );
/*
* Attach the "Prev", "Next" and "OK" buttons at the end of the window.
*/
printf( "\tframe $w.f\n" );
if ( toplevel )
printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
else
printf( "\tbutton $w.f.back -text \"OK\" \\\n" );
printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n",
menu_num );
printf( "\tbutton $w.f.next -text \"Next\" -underline 0\\\n" );
printf( "\t\t-width 15 -command $nextscript\n");
if ( menu_num == tot_menu_num ) {
printf( "\t$w.f.next configure -state disabled\n" );
/*
* this is a bit hackish but Alt-n must be rebound
* otherwise if the user press Alt-n on the last menu
* it will give him/her the next menu of one of the
* previous options
*/
printf( "\tbind all <Alt-n> \"puts \\\"no more menus\\\" \"\n");
}
else
{
/*
* I should be binding to $w not all - but if I do nehat I get the error "unknown path"
*/
printf( "\tbind all <Alt-n> $nextscript\n");
}
printf( "\tbutton $w.f.prev -text \"Prev\" -underline 0\\\n" );
printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\"\"\n",
menu_num, menu_num-1, menu_num-1 );
if ( menu_num == 1 ) {
printf( "\t$w.f.prev configure -state disabled\n" );
}
else
{
printf( "\tbind $w <Alt-p> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\";break\"\n",
menu_num, menu_num-1, menu_num-1 );
}
printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" );
printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" );
/*
* Lines between canvas and other areas of the window.
*/
printf( "\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n" );
printf( "\tpack $w.topline -side top -fill x\n\n" );
printf( "\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n" );
printf( "\tpack $w.botline -side bottom -fill x\n\n" );
/*
* The "config" frame contains the canvas and a scrollbar.
*/
printf( "\tframe $w.config\n" );
printf( "\tpack $w.config -fill y -expand on\n\n" );
printf( "\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n" );
printf( "\tpack $w.config.vscroll -side right -fill y\n\n" );
/*
* The scrollable canvas itself, where the real work (and mess) gets done.
*/
printf( "\tcanvas $w.config.canvas -height 1\\\n" );
printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" );
printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" );
printf( "\tframe $w.config.f\n" );
printf( "\tbind $w <Key-Down> \"$w.config.canvas yview scroll 1 unit;break;\"\n");
printf( "\tbind $w <Key-Up> \"$w.config.canvas yview scroll -1 unit;break;\"\n");
printf( "\tbind $w <Key-Next> \"$w.config.canvas yview scroll 1 page;break;\"\n");
printf( "\tbind $w <Key-Prior> \"$w.config.canvas yview scroll -1 page;break;\"\n");
printf( "\tbind $w <Key-Home> \"$w.config.canvas yview moveto 0;break;\"\n");
printf( "\tbind $w <Key-End> \"$w.config.canvas yview moveto 1 ;break;\"\n");
printf( "\tpack $w.config.canvas -side right -fill y\n" );
printf("\n\n");
}
/*
* Each proc we create needs a global declaration for any global variables we
* use. To minimize the size of the file, we set a flag each time we output
* a global declaration so we know whether we need to insert one for a
* given function or not.
*/
static void clear_globalflags(void)
{
int i;
for ( i = 1; i <= max_varnum; i++ )
vartable[i].global_written = 0;
}
/*
* Output a "global" line for a given variable. Also include the
* call to "vfix". (If vfix is not needed, then it's fine to just printf
* a "global" line).
*/
void global( const char *var )
{
printf( "\tglobal %s\n", var );
}
/*
* This function walks the chain of conditions that we got from cond.c
* and creates a TCL conditional to enable/disable a given widget.
*/
void generate_if( struct kconfig * cfg, struct condition * ocond,
int menu_num, int line_num )
{
struct condition * cond;
struct dependency * tmp;
struct kconfig * cfg1;
if ( line_num >= -1 )
{
if ( cfg->token == token_define_bool || cfg->token == token_define_hex
|| cfg->token == token_define_int || cfg->token == token_define_string
|| cfg->token == token_define_tristate || cfg->token == token_unset )
return;
if ( cfg->token == token_comment && line_num == -1 )
return;
}
else
{
if ( cfg->token == token_string || cfg->token == token_mainmenu_option )
return;
}
/*
* First write any global declarations we need for this conditional.
*/
for ( cond = ocond; cond != NULL; cond = cond->next )
{
switch ( cond->op )
{
default:
break;
case op_variable:
if ( ! vartable[cond->nameindex].global_written )
{
vartable[cond->nameindex].global_written = 1;
global( vartable[cond->nameindex].name );
}
break;
}
}
/*
* Now write this option.
*/
if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
{
vartable[cfg->nameindex].global_written = 1;
global( vartable[cfg->nameindex].name );
}
/*
* Generate the body of the conditional.
*/
printf( "\tif {" );
for ( cond = ocond; cond != NULL; cond = cond->next )
{
switch ( cond->op )
{
default:
break;
case op_bang: printf( " ! " ); break;
case op_eq: printf( " == " ); break;
case op_neq: printf( " != " ); break;
case op_and: printf( " && " ); break;
case op_and1: printf( " && " ); break;
case op_or: printf( " || " ); break;
case op_lparen: printf( "(" ); break;
case op_rparen: printf( ")" ); break;
case op_variable:
printf( "$%s", vartable[cond->nameindex].name );
break;
case op_constant:
if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
else if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
else if ( strcmp( cond->str, "" ) == 0 ) printf( "4" );
else
printf( "\"%s\"", cond->str );
break;
}
}
printf( "} then {" );
/*
* Generate a procedure call to write the value.
* This code depends on procedures in header.tk.
*/
if ( line_num >= -1 )
{
int modtoyes = 0;
switch ( cfg->token )
{
default:
printf( " }\n" );
break;
case token_dep_mbool:
modtoyes = 1;
case token_dep_bool:
printf( "\n" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
if ( ! vartable[get_varnum( tmp->name )].global_written )
{
global( tmp->name );
}
printf( "\tset tmpvar_dep [effective_dep [list" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
printf( " $%s", tmp->name );
printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
modtoyes );
printf( "if {$tmpvar_dep != 1" );
if (modtoyes)
printf( " && $tmpvar_dep != 2" );
printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};",
menu_num, line_num );
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d normal {y};",
menu_num, line_num );
printf( "}; " );
case token_bool:
if ( cfg->token == token_bool )
printf( "\n\t" );
printf( "configure_entry .menu%d.config.f.x%d normal {n l",
menu_num, line_num );
if ( cfg->token == token_bool )
printf( " y" );
printf( "}" );
printf( "} else {");
printf( "configure_entry .menu%d.config.f.x%d disabled {y n l}}\n",
menu_num, line_num );
break;
case token_choice_header:
printf( "configure_entry .menu%d.config.f.x%d normal {x l}",
menu_num, line_num );
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d disabled {x l}",
menu_num, line_num );
printf( "}\n" );
break;
case token_choice_item:
fprintf( stderr, "Internal error on token_choice_item\n" );
exit( 1 );
case token_dep_tristate:
printf( "\n" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
if ( ! vartable[get_varnum( tmp->name )].global_written )
{
global( tmp->name );
}
printf( "\tset tmpvar_dep [effective_dep [list" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
printf( " $%s", tmp->name );
printf( "]];set %s [sync_tristate $%s $tmpvar_dep];",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
printf( "\tif {$tmpvar_dep != 1} then {" );
printf( "configure_entry .menu%d.config.f.x%d disabled {y}",
menu_num, line_num );
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d normal {y}",
menu_num, line_num );
printf( "}; " );
printf( "if {$tmpvar_dep == 0} then {" );
printf( "configure_entry .menu%d.config.f.x%d disabled {m}",
menu_num, line_num );
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d normal {m}",
menu_num, line_num );
printf( "}; " );
case token_tristate:
if ( cfg->token == token_tristate )
{
printf( "\n\tconfigure_entry .menu%d.config.f.x%d normal {y}; ",
menu_num, line_num );
}
printf( "if {($CONFIG_MODULES == 1)} then {" );
printf( "configure_entry .menu%d.config.f.x%d normal {m}} else {",
menu_num, line_num );
printf( "configure_entry .menu%d.config.f.x%d disabled {m}}; ",
menu_num, line_num );
printf( "configure_entry .menu%d.config.f.x%d normal {n l}",
menu_num, line_num );
/*
* Or in a bit to the variable - this causes all of the radiobuttons
* to be deselected (i.e. not be red).
*/
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d disabled {y n m l}}\n",
menu_num, line_num );
break;
case token_hex:
case token_int:
case token_string:
printf( ".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ",
menu_num, line_num );
printf( ".menu%d.config.f.x%d.l configure -state normal; ",
menu_num, line_num );
printf( "} else {" );
printf( ".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ]; ",
menu_num, line_num );
printf( ".menu%d.config.f.x%d.l configure -state disabled}\n",
menu_num, line_num );
break;
case token_comment:
case token_mainmenu_option:
if ( line_num >= 0 )
{
printf( "configure_entry .menu%d.config.f.x%d normal {m}",
menu_num, line_num );
printf( "} else {" );
printf( "configure_entry .menu%d.config.f.x%d disabled {m}}\n",
menu_num, line_num );
}
else
printf( ".f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
menu_num, menu_num );
break;
}
}
else
{
int modtoyes = 0;
switch ( cfg->token )
{
default:
printf( " }\n" );
break;
case token_dep_mbool:
modtoyes = 1;
case token_dep_bool:
printf( "\n" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
if ( ! vartable[get_varnum( tmp->name )].global_written )
{
global( tmp->name );
}
printf( "\tset tmpvar_dep [effective_dep [list" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
printf( " $%s", tmp->name );
printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
modtoyes );
case token_bool:
if ( cfg->token == token_bool )
printf( "\n\t" );
printf( "set %s [expr $%s&15]",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
printf( "} else {");
printf( "set %s [expr $%s|16]}\n",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
break;
case token_choice_header:
printf( "} else {" );
for ( cfg1 = cfg->next;
cfg1 != NULL && cfg1->token == token_choice_item;
cfg1 = cfg1->next )
printf( "set %s 4;", vartable[cfg1->nameindex].name );
printf( "}\n" );
break;
case token_choice_item:
fprintf( stderr, "Internal error on token_choice_item\n" );
exit( 1 );
case token_define_bool:
case token_define_tristate:
if ( ! vartable[get_varnum( cfg->value )].global_written )
{
global( cfg->value );
}
printf( "set %s $%s }\n",
vartable[cfg->nameindex].name, cfg->value );
break;
case token_define_hex:
case token_define_int:
printf( "set %s %s }\n",
vartable[cfg->nameindex].name, cfg->value );
break;
case token_define_string:
printf( "set %s \"%s\" }\n",
vartable[cfg->nameindex].name, cfg->value );
break;
case token_dep_tristate:
printf( "\n" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
if ( ! vartable[get_varnum( tmp->name )].global_written )
{
global( tmp->name );
}
printf( "\tset tmpvar_dep [effective_dep [list" );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
printf( " $%s", tmp->name );
printf( "]]; set %s [sync_tristate $%s $tmpvar_dep]; ",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
case token_tristate:
if ( cfg->token == token_tristate )
printf( "if {($CONFIG_MODULES == 0) && ($%s == 2)} then {set %s 1}; ",
vartable[cfg->nameindex].name,
vartable[cfg->nameindex].name );
/*
* Or in a bit to the variable - this causes all of the radiobuttons
* to be deselected (i.e. not be red).
*/
printf( "set %s [expr $%s&15]",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
printf( "} else {" );
/*
* Clear the disable bit to enable the correct radiobutton.
*/
printf( "set %s [expr $%s|16]}\n",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
break;
case token_hex:
case token_int:
if ( cfg->value && *cfg->value == '$' )
{
int i = get_varnum( cfg->value+1 );
printf( "\n" );
if ( ! vartable[i].global_written )
{
global( vartable[i].name );
}
printf( "\t" );
}
if ( cfg->token == token_hex )
printf( "validate_hex " );
else if ( cfg->token == token_int )
printf( "validate_int " );
printf( "%s \"$%s\" %s}\n",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
cfg->value );
break;
case token_unset:
printf( "set %s 4}\n", vartable[cfg->nameindex].name );
break;
}
}
}
/*
* Generate a line that writes a variable to the output file.
*/
void generate_writeconfig( struct kconfig * cfg )
{
struct condition * cond;
struct dependency * tmp;
int depmod = 2;
/*
* Generate global declaration for this symbol.
*/
if ( cfg->token != token_comment )
{
if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
{
vartable[cfg->nameindex].global_written = 1;
global( vartable[cfg->nameindex].name );
}
if ( cfg->token == token_define_tristate || cfg->token == token_define_bool )
{
if ( ! vartable[get_varnum( cfg->value )].global_written )
{
vartable[get_varnum( cfg->value )].global_written = 1;
global( cfg->value );
}
}
else if ( cfg->nameindex <= 0 && cfg->token == token_choice_header )
{
printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
}
}
/*
* Generate global declarations for the condition chain.
*/
for ( cond = cfg->cond; cond != NULL; cond = cond->next )
{
switch( cond->op )
{
default:
break;
case op_variable:
if ( ! vartable[cond->nameindex].global_written )
{
vartable[cond->nameindex].global_written = 1;
global( vartable[cond->nameindex].name );
}
break;
}
}
/*
* Generate indentation.
*/
printf( "\t" );
/*
* Generate the conditional.
*/
if ( cfg->cond != NULL )
{
printf( "if {" );
for ( cond = cfg->cond; cond != NULL; cond = cond->next )
{
switch ( cond->op )
{
default: break;
case op_bang: printf( " ! " ); break;
case op_eq: printf( " == " ); break;
case op_neq: printf( " != " ); break;
case op_and: printf( " && " ); break;
case op_and1: printf( " && " ); break;
case op_or: printf( " || " ); break;
case op_lparen: printf( "(" ); break;
case op_rparen: printf( ")" ); break;
case op_variable:
printf( "$%s", vartable[cond->nameindex].name );
break;
case op_constant:
if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
else if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
else if ( strcmp( cond->str, "" ) == 0 ) printf( "4" );
else
printf( "\"%s\"", cond->str );
break;
}
}
printf( "} then {" );
}
/*
* Generate a procedure call to write the value.
* This code depends on the write_* procedures in header.tk.
*/
switch ( cfg->token )
{
default:
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_bool:
case token_tristate:
printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_choice_header:
/*
* This is funky code -- it fails if there were any conditionals.
* Fortunately all the conditionals got stripped off somewhere
* else.
*/
{
struct kconfig * cfg1;
for ( cfg1 = cfg->next;
cfg1 != NULL && cfg1->token == token_choice_item;
cfg1 = cfg1->next )
{
printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] 2 } else { write_tristate $cfg $autocfg %s 0 [list $notmod] 2 }",
-(cfg->nameindex), cfg1->label,
vartable[cfg1->nameindex].name,
vartable[cfg1->nameindex].name );
}
}
if ( cfg->cond != NULL )
printf( "}" );
printf( "\n" );
break;
case token_choice_item:
fprintf( stderr, "Internal error on token_choice_item\n" );
exit( 1 );
case token_comment:
printf( "write_comment $cfg $autocfg \"%s\"",
cfg->label );
if ( cfg->cond != NULL )
printf( "}" );
printf( "\n" );
break;
case token_define_bool:
case token_define_tristate:
if ( cfg->cond == NULL )
{
printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
}
else
{
printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n",
vartable[cfg->nameindex].name, cfg->value );
}
break;
case token_dep_mbool:
depmod = 1;
case token_dep_bool:
case token_dep_tristate:
printf( "write_tristate $cfg $autocfg %s $%s [list",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
for ( tmp = cfg->depend; tmp; tmp = tmp->next )
printf( " $%s", tmp->name );
printf( "] %d", depmod );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_define_hex:
printf( "write_hex $cfg $autocfg %s %s $notmod",
vartable[cfg->nameindex].name, cfg->value );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_define_int:
printf( "write_int $cfg $autocfg %s %s $notmod",
vartable[cfg->nameindex].name, cfg->value );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_define_string:
printf( "write_string $cfg $autocfg %s \"%s\" $notmod",
vartable[cfg->nameindex].name, cfg->value );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_hex:
printf( "write_hex $cfg $autocfg %s $%s $notmod",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_int:
printf( "write_int $cfg $autocfg %s $%s $notmod",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
case token_string:
printf( "write_string $cfg $autocfg %s \"$%s\" $notmod",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
if ( cfg->cond != NULL )
printf( " }" );
printf( "\n" );
break;
}
}
static void generate_update_var( struct kconfig * scfg, int menu_num )
{
struct kconfig * cfg;
if ( menu_num>0 )
{
printf( "proc update_define_menu%d {} {\n", menu_num );
printf( "\tupdate_define_mainmenu\n" );
}
else
printf( "proc update_define_mainmenu {} {\n" );
clear_globalflags();
global( "CONFIG_MODULES" );
vartable[ get_varnum( "CONFIG_MODULES" ) ].global_written = 1;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
if ( cfg->menu_number == menu_num && (cfg->token == token_define_bool || cfg->token == token_define_tristate
|| cfg->token == token_define_hex || cfg->token == token_define_int
|| cfg->token == token_define_string || cfg->token == token_unset
|| cfg->token == token_tristate) )
{
if ( ! vartable[cfg->nameindex].global_written )
{
vartable[cfg->nameindex].global_written = 1;
global( vartable[cfg->nameindex].name );
}
}
}
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
char tmp[20];
struct kconfig * cfg1;
if ( cfg->menu_number == menu_num )
{
switch ( cfg->token )
{
default:
case token_choice_item:
break;
case token_choice_header:
sprintf( tmp, "tmpvar_%d", -(cfg->nameindex) );
global( tmp );
for ( cfg1 = cfg->next;
cfg1 != NULL && cfg1->token == token_choice_item;
cfg1 = cfg1->next )
{
vartable[cfg1->nameindex].global_written = 1;
global( vartable[cfg1->nameindex].name );
printf( "\tif {$tmpvar_%d == \"%s\"} then {set %s 1} else {set %s 0}\n",
-(cfg->nameindex), cfg1->label,
vartable[cfg1->nameindex].name,
vartable[cfg1->nameindex].name );
}
break;
case token_bool:
case token_define_bool:
case token_define_tristate:
case token_define_hex:
case token_define_int:
case token_define_string:
case token_dep_bool:
case token_dep_tristate:
case token_dep_mbool:
case token_int:
case token_hex:
case token_mainmenu_option:
case token_tristate:
case token_unset:
if ( cfg->cond != NULL )
generate_if( cfg, cfg->cond, menu_num, -2 );
else switch ( cfg->token )
{
case token_tristate:
printf( "\n\tif {($CONFIG_MODULES == 0)} then {if {($%s == 2)} then {set %s 1}}\n",
vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
break;
case token_define_bool:
case token_define_tristate:
if ( ! vartable[get_varnum( cfg->value )].global_written )
{
vartable[get_varnum( cfg->value )].global_written = 1;
global( cfg->value );
}
printf( "\tset %s $%s\n", vartable[cfg->nameindex].name,
cfg->value );
break;
case token_define_hex:
case token_define_int:
printf( "\tset %s %s\n", vartable[cfg->nameindex].name,
cfg->value );
break;
case token_define_string:
printf( "\tset %s \"%s\"\n", vartable[cfg->nameindex].name,
cfg->value );
break;
case token_unset:
printf( "\tset %s 4\n", vartable[cfg->nameindex].name );
default:
break;
}
}
}
}
printf( "}\n\n\n" );
}
/*
* Generates the end of a menu procedure.
*/
static void end_proc( struct kconfig * scfg, int menu_num )
{
struct kconfig * cfg;
printf( "\n\n\n" );
printf( "\tfocus $w\n" );
printf( "\tupdate_active\n" );
printf( "\tglobal winx; global winy\n" );
if ( menu_first[menu_num]->menu_number != 0 )
{
printf( "\tif {[winfo exists .menu%d] == 0} then ",
menu_first[menu_num]->menu_number );
printf( "{menu%d .menu%d \"%s\"}\n",
menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number,
menu_first[menu_first[menu_num]->menu_number]->label );
printf( "\tset winx [expr [winfo x .menu%d]+30]; set winy [expr [winfo y .menu%d]+30]\n",
menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number );
}
else
printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" );
printf( "\tif {[winfo exists $w]} then {wm geometry $w +$winx+$winy}\n" );
/*
* Now that the whole window is in place, we need to wait for an "update"
* so we can tell the canvas what its virtual size should be.
*
* Unfortunately, this causes some ugly screen-flashing because the whole
* window is drawn, and then it is immediately resized. It seems
* unavoidable, though, since "frame" objects won't tell us their size
* until after an update, and "canvas" objects can't automatically pack
* around frames. Sigh.
*/
printf( "\tupdate idletasks\n" );
printf( "\tif {[winfo exists $w]} then {$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
printf( "\t$w.config.canvas configure \\\n" );
printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" );
printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" );
printf( "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n" );
/*
* If the whole canvas will fit in 3/4 of the screen height, do it;
* otherwise, resize to around 1/2 the screen and let us scroll.
*/
printf( "\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n" );
printf( "\tset scry [expr [winfo screenh $w] / 2]\n" );
printf( "\tset maxy [expr [winfo screenh $w] * 3 / 4]\n" );
printf( "\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n" );
printf( "\tif [expr $winy + $canvtotal < $maxy] {\n" );
printf( "\t\t$w.config.canvas configure -height $canvtotal\n" );
printf( "\t} else {\n" );
printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" );
printf( "\t\t}\n\t}\n" );
/*
* Limit the min/max window size. Height can vary, but not width,
* because of the limitations of canvas and our laziness.
*/
printf( "\tupdate idletasks\n" );
printf( "\tif {[winfo exists $w]} then {\n\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
printf( "\twm minsize $w [winfo width $w] 100\n\n" );
printf( "\twm deiconify $w\n" );
printf( "}\n}\n\n" );
/*
* Now we generate the companion procedure for the menu we just
* generated. This procedure contains all of the code to
* disable/enable widgets based upon the settings of the other
* widgets, and will be called first when the window is mapped,
* and each time one of the buttons in the window are clicked.
*/
printf( "proc update_menu%d {} {\n", menu_num );
/*
* Clear all of the booleans that are defined in this menu.
*/
clear_globalflags();
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
if ( cfg->menu_number == menu_num
&& cfg->token != token_mainmenu_option
&& cfg->token != token_choice_item )
{
if ( cfg->cond != NULL )
{
int i;
if ( (cfg->token == token_tristate || cfg->token == token_dep_tristate)
&& ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
{
global( "CONFIG_MODULES" );
vartable[i].global_written = 1;
}
generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line );
}
else
{
if ( cfg->token == token_tristate )
{
int i;
if ( ! vartable[cfg->nameindex].global_written )
{
vartable[cfg->nameindex].global_written = 1;
printf( "\tglobal %s\n", vartable[cfg->nameindex].name );
}
if ( ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
{
global( "CONFIG_MODULES" );
vartable[i].global_written = 1;
}
printf( "\n\tif {($CONFIG_MODULES == 1)} then {configure_entry .menu%d.config.f.x%d normal {m}} else {configure_entry .menu%d.config.f.x%d disabled {m}}\n",
menu_num, cfg->menu_line,
menu_num, cfg->menu_line );
}
}
}
else if ( cfg->token == token_mainmenu_option
&& cfg->menu_number == menu_num
&& cfg->cond != NULL )
{
generate_if( cfg, cfg->cond, menu_num, cfg->menu_line );
}
}
printf("}\n\n\n");
generate_update_var( scfg, menu_num );
}
/*
* This is the top level function for generating the tk script.
*/
void dump_tk_script( struct kconfig * scfg )
{
int menu_depth;
int menu_num [64];
int imenu, i;
int top_level_num = 0;
struct kconfig * cfg;
struct kconfig * cfg1 = NULL;
const char * name = "No Name";
/*
* Mark begin and end of each menu so I can omit submenus when walking
* over a parent menu.
*/
tot_menu_num = 0;
menu_depth = 0;
menu_num [0] = 0;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
switch ( cfg->token )
{
default:
break;
case token_mainmenu_name:
name = cfg->label;
break;
case token_mainmenu_option:
if ( ++menu_depth >= 64 )
{ fprintf( stderr, "menus too deep\n" ); exit( 1 ); }
if ( ++tot_menu_num >= 100 )
{ fprintf( stderr, "too many menus\n" ); exit( 1 ); }
menu_num [menu_depth] = tot_menu_num;
menu_first [tot_menu_num] = cfg;
menu_last [tot_menu_num] = cfg;
/*
* Note, that menu_number is set to the number of parent
* (upper level) menu.
*/
cfg->menu_number = menu_num[menu_depth - 1];
if ( menu_depth == 1 )
++top_level_num;
break;
case token_endmenu:
menu_last [menu_num [menu_depth]] = cfg;
/* flatten menus with proper scoping */
if ( --menu_depth < 0 )
{ fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); }
break;
case token_bool:
case token_choice_header:
case token_choice_item:
case token_comment:
case token_dep_bool:
case token_dep_tristate:
case token_dep_mbool:
case token_hex:
case token_int:
case token_string:
case token_tristate:
cfg->menu_number = menu_num[menu_depth];
if ( menu_depth == 0 )
{ fprintf( stderr, "statement not in menu\n" ); exit( 1 ); }
break;
case token_define_bool:
case token_define_hex:
case token_define_int:
case token_define_string:
case token_define_tristate:
case token_unset:
cfg->menu_number = menu_num[menu_depth];
break;
}
}
/*
* Generate menus per column setting.
* There are:
* four extra buttons for save/quit/load/store;
* one blank button
* add two to round up for division
*/
printf( "set menus_per_column %d\n", (top_level_num + 4 + 1 + 2) / 3 );
printf( "set total_menus %d\n\n", tot_menu_num );
printf( "proc toplevel_menu {num} {\n" );
for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
{
int parent = 1;
if ( menu_first[imenu]->menu_number == 0 )
parent = menu_first[imenu]->menu_number;
else
printf( "\tif {$num == %d} then {return %d}\n",
imenu, menu_first[imenu]->menu_number );
}
printf( "\treturn $num\n}\n\n" );
/*
* Generate the menus.
*/
printf( "mainmenu_name \"%s\"\n", name );
for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
{
int menu_line = 0;
int nr_submenu = imenu;
int menu_name_omitted = 0;
int opt_count = 0;
clear_globalflags();
start_proc( menu_first[imenu]->label, imenu,
!menu_first[imenu]->menu_number );
for ( cfg = menu_first[imenu]->next; cfg != NULL && cfg != menu_last[imenu]; cfg = cfg->next )
{
switch ( cfg->token )
{
default:
break;
case token_mainmenu_option:
while ( menu_first[++nr_submenu]->menu_number > imenu )
;
cfg->menu_line = menu_line++;
printf( "\tsubmenu $w.config.f %d %d \"%s\" %d\n",
cfg->menu_number, cfg->menu_line, cfg->label, nr_submenu );
cfg = menu_last[nr_submenu];
break;
case token_comment:
if ( !cfg->menu_line && !menu_name_omitted )
{
cfg->menu_line = -1;
menu_name_omitted = 1;
}
else
{
menu_name_omitted = 1;
cfg->menu_line = menu_line++;
printf( "\tcomment $w.config.f %d %d \"%s\"\n",
cfg->menu_number, cfg->menu_line, cfg->label );
}
break;
case token_bool:
cfg->menu_line = menu_line++;
printf( "\tbool $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_choice_header:
/*
* I need the first token_choice_item to pick out the right
* help text from Documentation/Configure.help.
*/
cfg->menu_line = menu_line++;
printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
printf( "\tminimenu $w.config.f %d %d \"%s\" tmpvar_%d %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
-(cfg->nameindex), vartable[cfg->next->nameindex].name );
printf( "\tmenu $w.config.f.x%d.x.menu -tearoffcommand \"menutitle \\\"%s\\\"\"\n",
cfg->menu_line, cfg->label );
cfg1 = cfg;
opt_count = 0;
break;
case token_choice_item:
/* note: no menu line; uses choice header menu line */
printf( "\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable tmpvar_%d -value \"%s\" -command \"update_active\"\n",
cfg1->menu_line, cfg->label, -(cfg1->nameindex),
cfg->label );
opt_count++;
if ( cfg->next && cfg->next->token != token_choice_item ) {
/* last option in the menu */
printf( "\tmenusplit $w $w.config.f.x%d.x.menu %d\n",
cfg1->menu_line, opt_count );
}
break;
case token_dep_bool:
case token_dep_mbool:
cfg->menu_line = menu_line++;
printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_dep_tristate:
cfg->menu_line = menu_line++;
printf( "\tdep_tristate $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_hex:
cfg->menu_line = menu_line++;
printf( "\thex $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_int:
cfg->menu_line = menu_line++;
printf( "\tint $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_string:
cfg->menu_line = menu_line++;
printf( "\tistring $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
case token_tristate:
cfg->menu_line = menu_line++;
printf( "\ttristate $w.config.f %d %d \"%s\" %s\n",
cfg->menu_number, cfg->menu_line, cfg->label,
vartable[cfg->nameindex].name );
break;
}
}
end_proc( scfg, imenu );
}
/*
* The top level menu also needs an update function. When we update a
* submenu, we may need to disable one or more of the submenus on
* the top level menu, and this procedure will ensure that things are
* correct.
*/
clear_globalflags();
printf( "proc update_mainmenu {} {\n" );
for ( imenu = 1; imenu <= tot_menu_num; imenu++ )
{
if ( menu_first[imenu]->cond != NULL && menu_first[imenu]->menu_number == 0 )
generate_if( menu_first[imenu], menu_first[imenu]->cond, imenu, -1 );
}
printf( "}\n\n\n" );
clear_globalflags();
/*
* Generate code to load the default settings into the variables.
* The script in tail.tk will attempt to load .config,
* which may override these settings, but that's OK.
*/
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
switch ( cfg->token )
{
default:
break;
case token_bool:
case token_choice_item:
case token_dep_bool:
case token_dep_tristate:
case token_dep_mbool:
case token_tristate:
if ( ! vartable[cfg->nameindex].global_written )
{
printf( "set %s 0\n", vartable[cfg->nameindex].name );
vartable[cfg->nameindex].global_written = 1;
}
break;
case token_choice_header:
printf( "set tmpvar_%d \"(not set)\"\n", -(cfg->nameindex) );
break;
case token_hex:
case token_int:
if ( ! vartable[cfg->nameindex].global_written )
{
printf( "set %s %s\n", vartable[cfg->nameindex].name, cfg->value ? cfg->value : "0" );
vartable[cfg->nameindex].global_written = 1;
}
break;
case token_string:
if ( ! vartable[cfg->nameindex].global_written )
{
printf( "set %s \"%s\"\n", vartable[cfg->nameindex].name, cfg->value );
vartable[cfg->nameindex].global_written = 1;
}
break;
}
}
/*
* Define to an empty value all other variables (which are never defined)
*/
for ( i = 1; i <= max_varnum; i++ )
{
if ( ! vartable[i].global_written
&& strncmp( vartable[i].name, "CONSTANT_", 9 ) )
printf( "set %s 4\n", vartable[i].name );
}
/*
* Generate a function to write all of the variables to a file.
*/
printf( "proc writeconfig {file1 file2} {\n" );
printf( "\tset cfg [open $file1 w]\n" );
printf( "\tset autocfg [open $file2 w]\n" );
printf( "\tset notmod 1\n" );
printf( "\tset notset 0\n" );
printf( "\tputs $cfg \"#\"\n");
printf( "\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
printf( "\tputs $cfg \"#\"\n" );
printf( "\tputs $autocfg \"/*\"\n" );
printf( "\tputs $autocfg \" * Automatically generated C config: don't edit\"\n" );
printf( "\tputs $autocfg \" */\"\n" );
printf( "\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n" );
clear_globalflags();
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
switch ( cfg->token )
{
default:
break;
case token_bool:
case token_choice_header:
case token_comment:
case token_define_bool:
case token_define_hex:
case token_define_int:
case token_define_string:
case token_define_tristate:
case token_dep_bool:
case token_dep_tristate:
case token_dep_mbool:
case token_hex:
case token_int:
case token_string:
case token_tristate:
generate_writeconfig( cfg );
break;
}
}
printf( "\tclose $cfg\n" );
printf( "\tclose $autocfg\n" );
printf( "}\n\n\n" );
/*
* Generate a simple function that updates the master choice
* variable depending upon what values were loaded from a .config
* file.
*/
printf( "proc clear_choices { } {\n" );
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
if ( cfg->token == token_choice_header )
{
for ( cfg1 = cfg->next;
cfg1 != NULL && cfg1->token == token_choice_item;
cfg1 = cfg1->next )
{
printf( "\tglobal %s; set %s 0\n",
vartable[cfg1->nameindex].name,
vartable[cfg1->nameindex].name );
}
}
}
printf( "}\n\n\n" );
printf( "proc update_choices { } {\n" );
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
if ( cfg->token == token_choice_header )
{
printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
printf("\tset tmpvar_%d \"%s\"\n", -(cfg->nameindex), cfg->value);
for ( cfg1 = cfg->next;
cfg1 != NULL && cfg1->token == token_choice_item;
cfg1 = cfg1->next )
{
printf( "\tglobal %s\n", vartable[cfg1->nameindex].name );
printf( "\tif { $%s == 1 } then { set tmpvar_%d \"%s\" }\n",
vartable[cfg1->nameindex].name,
-(cfg->nameindex), cfg1->label );
}
}
}
printf( "}\n\n\n" );
generate_update_var( scfg, 0 );
/*
* That's it. We are done. The output of this file will have header.tk
* prepended and tail.tk appended to create an executable wish script.
*/
}
/*
* tkparse.c
*
* Eric Youngdale was the original author of xconfig.
* Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
*
* Parse a config.in file and translate it to a wish script.
* This task has three parts:
*
* tkparse.c tokenize the input
* tkcond.c transform 'if ...' statements
* tkgen.c generate output
*
* Change History
*
* 7 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
* - Teach dep_tristate about a few literals, such as:
* dep_tristate 'foo' CONFIG_FOO m
* Also have it print an error message and exit on some parse failures.
*
* 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
* - Don't fclose stdin. Thanks to Tony Hoyle for nailing this one.
*
* 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
* - Steam-clean this file. I tested this by generating kconfig.tk for
* every architecture and comparing it character-for-character against
* the output of the old tkparse.
*
* 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
* - Remove bug-compatible code.
*
* 07 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
* - Submenus implemented,
* - plenty of option updating/displaying fixes,
* - dep_bool, define_hex, define_int, define_string, define_tristate and
* undef implemented,
* - dep_tristate fixed to support multiple dependencies,
* - handling of variables with an empty value implemented,
* - value checking for int and hex fields,
* - more checking during condition parsing; choice variables are treated as
* all others now,
*
* TO DO:
* - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
* you are interested in working on the replacement.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tkparse.h"
static struct kconfig * config_list = NULL;
static struct kconfig * config_last = NULL;
static const char * current_file = "<unknown file>";
static int lineno = 0;
static void do_source( const char * );
#undef strcmp
int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
#define strcmp my_strcmp
/*
* Report a syntax error.
*/
static void syntax_error( const char * msg )
{
fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg );
exit( 1 );
}
/*
* Find index of a specific variable in the symbol table.
* Create a new entry if it does not exist yet.
*/
struct variable *vartable;
int max_varnum = 0;
static int vartable_size = 0;
int get_varnum( char * name )
{
int i;
for ( i = 1; i <= max_varnum; i++ )
if ( strcmp( vartable[i].name, name ) == 0 )
return i;
while (max_varnum+1 >= vartable_size) {
vartable = realloc(vartable, (vartable_size += 1000)*sizeof(*vartable));
if (!vartable) {
fprintf(stderr, "tkparse realloc vartable failed\n");
exit(1);
}
}
vartable[++max_varnum].name = malloc( strlen( name )+1 );
strcpy( vartable[max_varnum].name, name );
return max_varnum;
}
/*
* Get a string.
*/
static const char * get_string( const char * pnt, char ** label )
{
const char * word;
word = pnt;
for ( ; ; )
{
if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' )
break;
pnt++;
}
*label = malloc( pnt - word + 1 );
memcpy( *label, word, pnt - word );
(*label)[pnt - word] = '\0';
if ( *pnt != '\0' )
pnt++;
return pnt;
}
/*
* Get a quoted string.
* Insert a '\' before any characters that need quoting.
*/
static const char * get_qstring( const char * pnt, char ** label )
{
char quote_char;
char newlabel [2048];
char * pnt1;
/* advance to the open quote */
for ( ; ; )
{
if ( *pnt == '\0' )
return pnt;
quote_char = *pnt++;
if ( quote_char == '"' || quote_char == '\'' )
break;
}
/* copy into an intermediate buffer */
pnt1 = newlabel;
for ( ; ; )
{
if ( *pnt == '\0' )
syntax_error( "unterminated quoted string" );
if ( *pnt == quote_char && pnt[-1] != '\\' )
break;
/* copy the character, quoting if needed */
if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' )
*pnt1++ = '\\';
*pnt1++ = *pnt++;
}
/* copy the label into a permanent location */
*pnt1++ = '\0';
*label = (char *) malloc( pnt1 - newlabel );
memcpy( *label, newlabel, pnt1 - newlabel );
/* skip over last quote and next whitespace */
pnt++;
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
return pnt;
}
/*
* Get a quoted or unquoted string. It is recognized by the first
* non-white character. '"' and '"' are not allowed inside the string.
*/
static const char * get_qnqstring( const char * pnt, char ** label )
{
char quote_char;
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
if ( *pnt == '\0' )
return pnt;
quote_char = *pnt;
if ( quote_char == '"' || quote_char == '\'' )
return get_qstring( pnt, label );
else
return get_string( pnt, label );
}
/*
* Tokenize an 'if' statement condition.
*/
static struct condition * tokenize_if( const char * pnt )
{
struct condition * list;
struct condition * last;
struct condition * prev;
/* eat the open bracket */
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
if ( *pnt != '[' )
syntax_error( "bad 'if' condition" );
pnt++;
list = last = NULL;
for ( ; ; )
{
struct condition * cond;
/* advance to the next token */
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
if ( *pnt == '\0' )
syntax_error( "unterminated 'if' condition" );
if ( *pnt == ']' )
return list;
/* allocate a new token */
cond = malloc( sizeof(*cond) );
memset( cond, 0, sizeof(*cond) );
if ( last == NULL )
{ list = last = cond; prev = NULL; }
else
{ prev = last; last->next = cond; last = cond; }
/* determine the token value */
if ( *pnt == '-' && pnt[1] == 'a' )
{
if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
syntax_error( "incorrect argument" );
cond->op = op_and; pnt += 2; continue;
}
if ( *pnt == '-' && pnt[1] == 'o' )
{
if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
syntax_error( "incorrect argument" );
cond->op = op_or; pnt += 2; continue;
}
if ( *pnt == '!' && pnt[1] == '=' )
{
if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
syntax_error( "incorrect argument" );
cond->op = op_neq; pnt += 2; continue;
}
if ( *pnt == '=' )
{
if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
syntax_error( "incorrect argument" );
cond->op = op_eq; pnt += 1; continue;
}
if ( *pnt == '!' )
{
if ( prev && ( prev->op != op_and && prev->op != op_or
&& prev->op != op_bang ) )
syntax_error( "incorrect argument" );
cond->op = op_bang; pnt += 1; continue;
}
if ( *pnt == '"' )
{
const char * word;
if ( prev && ( prev->op == op_variable || prev->op == op_constant ) )
syntax_error( "incorrect argument" );
/* advance to the word */
pnt++;
if ( *pnt == '$' )
{ cond->op = op_variable; pnt++; }
else
{ cond->op = op_constant; }
/* find the end of the word */
word = pnt;
for ( ; ; )
{
if ( *pnt == '\0' )
syntax_error( "unterminated double quote" );
if ( *pnt == '"' )
break;
pnt++;
}
/* store a copy of this word */
{
char * str = malloc( pnt - word + 1 );
memcpy( str, word, pnt - word );
str [pnt - word] = '\0';
if ( cond->op == op_variable )
{
cond->nameindex = get_varnum( str );
free( str );
}
else /* op_constant */
{
cond->str = str;
}
}
pnt++;
continue;
}
/* unknown token */
syntax_error( "bad if condition" );
}
}
/*
* Tokenize a choice list. Choices appear as pairs of strings;
* note that I am parsing *inside* the double quotes. Ugh.
*/
static const char * tokenize_choices( struct kconfig * cfg_choose,
const char * pnt )
{
int default_checked = 0;
for ( ; ; )
{
struct kconfig * cfg;
char * buffer = malloc( 64 );
/* skip whitespace */
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
if ( *pnt == '\0' )
return pnt;
/* allocate a new kconfig line */
cfg = malloc( sizeof(*cfg) );
memset( cfg, 0, sizeof(*cfg) );
if ( config_last == NULL )
{ config_last = config_list = cfg; }
else
{ config_last->next = cfg; config_last = cfg; }
/* fill out the line */
cfg->token = token_choice_item;
cfg->cfg_parent = cfg_choose;
pnt = get_string( pnt, &cfg->label );
if ( ! default_checked &&
! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) )
{
default_checked = 1;
free( cfg_choose->value );
cfg_choose->value = cfg->label;
}
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
}
if ( ! default_checked )
syntax_error( "bad 'choice' default value" );
return pnt;
}
/*
* Tokenize one line.
*/
static void tokenize_line( const char * pnt )
{
static struct kconfig * last_menuoption = NULL;
enum e_token token;
struct kconfig * cfg;
struct dependency ** dep_ptr;
char * buffer = malloc( 64 );
/* skip white space */
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
/*
* categorize the next token
*/
#define match_token(t, s) \
if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; }
token = token_UNKNOWN;
switch ( *pnt )
{
default:
break;
case '#':
case '\0':
return;
case 'b':
match_token( token_bool, "bool" );
break;
case 'c':
match_token( token_choice_header, "choice" );
match_token( token_comment, "comment" );
break;
case 'd':
match_token( token_define_bool, "define_bool" );
match_token( token_define_hex, "define_hex" );
match_token( token_define_int, "define_int" );
match_token( token_define_string, "define_string" );
match_token( token_define_tristate, "define_tristate" );
match_token( token_dep_bool, "dep_bool" );
match_token( token_dep_mbool, "dep_mbool" );
match_token( token_dep_tristate, "dep_tristate" );
break;
case 'e':
match_token( token_else, "else" );
match_token( token_endmenu, "endmenu" );
break;
case 'f':
match_token( token_fi, "fi" );
break;
case 'h':
match_token( token_hex, "hex" );
break;
case 'i':
match_token( token_if, "if" );
match_token( token_int, "int" );
break;
case 'm':
match_token( token_mainmenu_name, "mainmenu_name" );
match_token( token_mainmenu_option, "mainmenu_option" );
break;
case 's':
match_token( token_source, "source" );
match_token( token_string, "string" );
break;
case 't':
match_token( token_then, "then" );
match_token( token_tristate, "tristate" );
break;
case 'u':
match_token( token_unset, "unset" );
break;
}
#undef match_token
if ( token == token_source )
{
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
do_source( pnt );
return;
}
if ( token == token_then )
{
if ( config_last != NULL && config_last->token == token_if )
return;
syntax_error( "bogus 'then'" );
}
#if 0
if ( token == token_unset )
{
fprintf( stderr, "Ignoring 'unset' command\n" );
return;
}
#endif
if ( token == token_UNKNOWN )
syntax_error( "unknown command" );
/*
* Allocate an item.
*/
cfg = malloc( sizeof(*cfg) );
memset( cfg, 0, sizeof(*cfg) );
if ( config_last == NULL )
{ config_last = config_list = cfg; }
else
{ config_last->next = cfg; config_last = cfg; }
/*
* Tokenize the arguments.
*/
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
cfg->token = token;
switch ( token )
{
default:
syntax_error( "unknown token" );
case token_bool:
case token_tristate:
pnt = get_qstring ( pnt, &cfg->label );
pnt = get_string ( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
break;
case token_choice_header:
{
static int choose_number = 0;
char * choice_list;
pnt = get_qstring ( pnt, &cfg->label );
pnt = get_qstring ( pnt, &choice_list );
pnt = get_string ( pnt, &cfg->value );
cfg->nameindex = -(choose_number++);
tokenize_choices( cfg, choice_list );
free( choice_list );
}
break;
case token_comment:
pnt = get_qstring(pnt, &cfg->label);
if ( last_menuoption != NULL )
{
pnt = get_qstring(pnt, &cfg->label);
if (cfg->label == NULL)
syntax_error( "missing comment text" );
last_menuoption->label = cfg->label;
last_menuoption = NULL;
}
break;
case token_define_bool:
case token_define_tristate:
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
if ( ( pnt[0] == 'Y' || pnt[0] == 'M' || pnt[0] == 'N'
|| pnt[0] == 'y' || pnt[0] == 'm' || pnt[0] == 'n' )
&& ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
{
if ( *pnt == 'n' || *pnt == 'N' ) cfg->value = strdup( "CONSTANT_N" );
else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = strdup( "CONSTANT_Y" );
else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = strdup( "CONSTANT_M" );
}
else if ( *pnt == '$' )
{
pnt++;
pnt = get_string( pnt, &cfg->value );
}
else
{
syntax_error( "unknown define_bool value" );
}
get_varnum( cfg->value );
break;
case token_define_hex:
case token_define_int:
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
pnt = get_string( pnt, &cfg->value );
break;
case token_define_string:
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
pnt = get_qnqstring( pnt, &cfg->value );
if (cfg->value == NULL)
syntax_error( "missing value" );
break;
case token_dep_bool:
case token_dep_mbool:
case token_dep_tristate:
pnt = get_qstring ( pnt, &cfg->label );
pnt = get_string ( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
dep_ptr = &(cfg->depend);
do {
*dep_ptr = (struct dependency *) malloc( sizeof( struct dependency ) );
(*dep_ptr)->next = NULL;
if ( ( pnt[0] == 'Y' || pnt[0] == 'M' || pnt[0] == 'N'
|| pnt[0] == 'y' || pnt[0] == 'm' || pnt[0] == 'n' )
&& ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
{
/* dep_tristate 'foo' CONFIG_FOO m */
if ( pnt[0] == 'Y' || pnt[0] == 'y' )
(*dep_ptr)->name = strdup( "CONSTANT_Y" );
else if ( pnt[0] == 'N' || pnt[0] == 'n' )
(*dep_ptr)->name = strdup( "CONSTANT_N" );
else
(*dep_ptr)->name = strdup( "CONSTANT_M" );
pnt++;
get_varnum( (*dep_ptr)->name );
}
else if ( *pnt == '$' )
{
pnt++;
pnt = get_string( pnt, &(*dep_ptr)->name );
get_varnum( (*dep_ptr)->name );
}
else
{
syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" );
}
dep_ptr = &(*dep_ptr)->next;
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
} while ( *pnt );
/*
* Create a conditional for this object's dependencies.
*/
{
char fake_if [1024];
struct dependency * dep;
struct condition ** cond_ptr;
int first = 1;
cond_ptr = &(cfg->cond);
for ( dep = cfg->depend; dep; dep = dep->next )
{
if ( token == token_dep_tristate
&& ! strcmp( dep->name, "CONSTANT_M" ) )
{
continue;
}
if ( first )
{
first = 0;
}
else
{
*cond_ptr = malloc( sizeof(struct condition) );
memset( *cond_ptr, 0, sizeof(struct condition) );
(*cond_ptr)->op = op_and;
cond_ptr = &(*cond_ptr)->next;
}
*cond_ptr = malloc( sizeof(struct condition) );
memset( *cond_ptr, 0, sizeof(struct condition) );
(*cond_ptr)->op = op_lparen;
if ( token == token_dep_bool )
sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then",
dep->name, dep->name );
else
sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then",
dep->name, dep->name, dep->name );
(*cond_ptr)->next = tokenize_if( fake_if );
while ( *cond_ptr )
cond_ptr = &(*cond_ptr)->next;
*cond_ptr = malloc( sizeof(struct condition) );
memset( *cond_ptr, 0, sizeof(struct condition) );
(*cond_ptr)->op = op_rparen;
cond_ptr = &(*cond_ptr)->next;
}
}
break;
case token_else:
case token_endmenu:
case token_fi:
break;
case token_hex:
case token_int:
pnt = get_qstring ( pnt, &cfg->label );
pnt = get_string ( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
pnt = get_string ( pnt, &cfg->value );
break;
case token_string:
pnt = get_qstring ( pnt, &cfg->label );
pnt = get_string ( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
pnt = get_qnqstring ( pnt, &cfg->value );
if (cfg->value == NULL)
syntax_error( "missing initial value" );
break;
case token_if:
cfg->cond = tokenize_if( pnt );
break;
case token_mainmenu_name:
pnt = get_qstring( pnt, &cfg->label );
break;
case token_mainmenu_option:
if ( strncmp( pnt, "next_comment", 12 ) == 0 )
last_menuoption = cfg;
else
pnt = get_qstring( pnt, &cfg->label );
break;
case token_unset:
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
while (*pnt)
{
cfg->next = (struct kconfig *) malloc( sizeof(struct kconfig) );
memset( cfg->next, 0, sizeof(struct kconfig) );
cfg = cfg->next;
cfg->token = token_unset;
pnt = get_string( pnt, &buffer );
cfg->nameindex = get_varnum( buffer );
while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
}
break;
}
return;
}
/*
* Implement the "source" command.
*/
static void do_source( const char * filename )
{
char buffer [2048];
FILE * infile;
const char * old_file;
int old_lineno;
int offset;
/* open the file */
if ( strcmp( filename, "-" ) == 0 )
infile = stdin;
else
infile = fopen( filename, "r" );
/* if that failed, try ../filename */
if ( infile == NULL )
{
sprintf( buffer, "../%s", filename );
infile = fopen( buffer, "r" );
}
if ( infile == NULL )
{
sprintf( buffer, "unable to open %s", filename );
syntax_error( buffer );
}
/* push the new file name and line number */
old_file = current_file;
old_lineno = lineno;
current_file = filename;
lineno = 0;
/* read and process lines */
for ( offset = 0; ; )
{
char * pnt;
/* read a line */
fgets( buffer + offset, sizeof(buffer) - offset, infile );
if ( feof( infile ) )
break;
lineno++;
/* strip the trailing return character */
pnt = buffer + strlen(buffer) - 1;
if ( *pnt == '\n' )
*pnt-- = '\0';
/* eat \ NL pairs */
if ( *pnt == '\\' )
{
offset = pnt - buffer;
continue;
}
/* tokenize this line */
tokenize_line( buffer );
offset = 0;
}
/* that's all, folks */
if ( infile != stdin )
fclose( infile );
current_file = old_file;
lineno = old_lineno;
return;
}
/*
* Main program.
*/
int main( int argc, const char * argv [] )
{
do_source ( "-" );
fix_conditionals ( config_list );
dump_tk_script ( config_list );
free(vartable);
return 0;
}
/*
* tkparse.h
*/
/*
* Token types (mostly statement types).
*/
enum e_token
{
token_UNKNOWN,
token_bool,
token_choice_header,
token_choice_item,
token_comment,
token_define_bool,
token_define_hex,
token_define_int,
token_define_string,
token_define_tristate,
token_dep_bool,
token_dep_mbool,
token_dep_tristate,
token_else,
token_endmenu,
token_fi,
token_hex,
token_if,
token_int,
token_mainmenu_name,
token_mainmenu_option,
token_source,
token_string,
token_then,
token_tristate,
token_unset,
};
/*
* Operator types for conditionals.
*/
enum operator
{
op_eq,
op_neq,
op_and,
op_and1,
op_or,
op_bang,
op_lparen,
op_rparen,
op_constant,
op_variable,
op_true,
op_false,
op_nuked
};
/*
* Conditions come in linked lists.
* Some operators take strings:
*
* op_constant "foo"
* op_variable "$ARCH", "$CONFIG_PMAC", "$CONFIG_EXPERIMENTAL"
*
* Most "$..." constructs refer to a variable which is defined somewhere
* in the script. Note that it is legal to test variables which are never
* defined, such as variables that are meaningful only on other architectures.
*/
struct condition
{
struct condition * next;
enum operator op;
const char * str; /* op_constant */
int nameindex; /* op_variable */
};
/*
* Dependency list for dep_bool, dep_mbool, dep_tristate
*/
struct dependency
{
char * name;
struct dependency * next;
};
/*
* A statement from a config.in file
*/
struct kconfig
{
struct kconfig * next;
enum e_token token;
int nameindex;
char * label;
char * value;
struct condition * cond;
struct dependency * depend; /* token_dep_tristate */
struct kconfig * cfg_parent; /* token_choice_item */
/* used only in tkgen.c */
int menu_number;
int menu_line;
struct kconfig * menu_next;
};
struct variable
{
char * name;
char defined;
char global_written;
};
extern struct variable *vartable;
extern int max_varnum;
/*
* Prototypes
*/
extern void fix_conditionals ( struct kconfig * scfg ); /* tkcond.c */
extern void dump_tk_script ( struct kconfig * scfg ); /* tkgen.c */
extern int get_varnum ( char * name ); /* tkparse.c */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment