A bash-script using config.in for kernel config menu

Bernhard Kaindl (bkaindl@ping.at)
Mon, 18 Sep 1995 08:02:10 +0200 (MET DST)


I have posted an earlyer version already, but I think it get
lost, so now, I send my current version which has bugs fixes and
enhancements over this version.

Attached is a patch for 1.3.27, but it should work with any kernel!

The differences of this script to the other menu scripts are:
It don't uses curses, dialog, perl, or thelike.
It uses arch/i386/config.in to present the menu and uses .config!

This means:
When config.in is changed, it's menu refect the changes!

You can continue to patch the kernel and it's config-rules in
arch/i386/config.in, configure it with *new* rules, without
doing anything to get the menu working, it works simply.

E.g.: When Linus changes CONFIG_SOUND from BOOL to TRISTATE,
(as in pre-1.3.28) it gives you the option to build sound
as a module of course!(only a tiny example)

Structure:
A few lines added a config.in to mark which comments are possible main
menu options and Configure.menu is ready. I have included a patch to
arch/i386/config.in and to arch/sparc/config.in, look at it, and you
can also patch arch/mips/config.in.

Oops: If a menu like 'Network device support' has many types of cards
enabled, the menu wouldn't fit on screen. For now, redisplay it and use
^S/^Q for stop/start or scroll back with SHIFT-PGUP.

It is called by 'make menuconfig'.

I have only tested it for arch/[i386|sparc]/config.in, it lacks the
choice-function for the arch/alpha/config.in yet, but it works for me.

Cheers,

Bernhard

PS: I haven't compressed it to allow people can take a look at it before
giving it a spin. BTW, any comments are welcome. I will be proud if alike of
this may be used in the standard tree.

diff -Nru linux-1.3.27/Makefile linux/Makefile
--- linux-1.3.27/Makefile Mon Sep 18 05:50:28 1995
+++ linux/Makefile Mon Sep 18 06:01:09 1995
@@ -134,6 +134,9 @@
oldconfig: symlinks
$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in

+menuconfig: symlinks
+ $(CONFIG_SHELL) scripts/Configure.menu arch/$(ARCH)/config.in
+
config: symlinks
$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in

diff -Nru linux-1.3.27/arch/i386/config.in linux/arch/i386/config.in
--- linux-1.3.27/arch/i386/config.in Mon Sep 18 05:50:28 1995
+++ linux/arch/i386/config.in Mon Sep 18 07:31:42 1995
@@ -2,7 +2,9 @@
# For a description of the syntax of this configuration file,
# see the Configure script.
#
+mainmenu_name "Linux Kernel Configuration"

+mainmenu_option next_comment
comment 'General setup'

bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
@@ -41,10 +43,12 @@
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
#fi

+mainmenu_option next_comment
comment 'Loadable module support'
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n

if [ "$CONFIG_NET" = "y" ]; then
+mainmenu_option next_comment
comment 'Networking options'
bool 'TCP/IP networking' CONFIG_INET y
if [ "$CONFIG_INET" = "y" ]; then
@@ -76,6 +80,7 @@
fi
fi

+mainmenu_option next_comment
comment 'SCSI support'

bool 'SCSI support' CONFIG_SCSI y
@@ -97,6 +102,7 @@

bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n

+mainmenu_option next_comment
comment 'SCSI low-level drivers'

tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
@@ -126,6 +132,7 @@

if [ "$CONFIG_NET" = "y" ]; then

+mainmenu_option next_comment
comment 'Network device support'

bool 'Network device support' CONFIG_NETDEVICES y
@@ -219,6 +226,7 @@
fi
fi

+mainmenu_option next_comment
comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'

bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n
@@ -244,6 +252,7 @@
bool 'Experimental Sanyo H94A CDROM support' CONFIG_SJCD n
fi

+mainmenu_option next_comment
comment 'Filesystems'

tristate 'Standard (minix) fs support' CONFIG_MINIX_FS y
@@ -263,6 +272,7 @@
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS n

+mainmenu_option next_comment
comment 'character devices'

bool 'Cyclades async mux support' CONFIG_CYCLADES n
@@ -301,10 +311,12 @@
int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
fi

+mainmenu_option next_comment
comment 'Sound'

-bool 'Sound card support' CONFIG_SOUND n
+tristate 'Sound card support' CONFIG_SOUND n

+mainmenu_option next_comment
comment 'Kernel hacking'

#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
diff -Nru linux-1.3.27/arch/sparc/config.in linux/arch/sparc/config.in
--- linux-1.3.27/arch/sparc/config.in Mon Sep 18 06:46:05 1995
+++ linux/arch/sparc/config.in Mon Sep 18 07:14:21 1995
@@ -8,10 +8,12 @@
# For a description of the syntax of this configuration file,
# see the Configure script.
#
+mainmenu_name 'Sparc-Linux Kernel Configuration'

echo "#define CONFIG_SPARCDEVS 1" >> $CONFIG_H
echo "CONFIG_SPARCDEVS=y" >> $CONFIG

+mainmenu_option next_comment
comment 'Sparc Kernel setup'

bool 'Sun floppy controller support' CONFIG_BLK_DEV_SUNFD n
@@ -21,6 +23,7 @@
bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y

if [ "$CONFIG_NET" = "y" ]; then
+mainmenu_option next_comment
comment 'Networking options'
bool 'TCP/IP networking' CONFIG_INET y
if [ "$CONFIG_INET" "=" "y" ]; then
@@ -38,6 +41,7 @@
#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
fi

+mainmenu_option next_comment
comment 'SCSI support'

bool 'SCSI support?' CONFIG_SCSI n
@@ -64,6 +68,7 @@

if [ "$CONFIG_NET" = "y" ]; then

+mainmenu_option next_comment
comment 'Network device support'

bool 'Network device support?' CONFIG_NETDEVICES y
@@ -86,6 +91,7 @@
fi
fi

+mainmenu_option next_comment
comment 'Filesystems'

bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
@@ -106,6 +112,7 @@
bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n


+mainmenu_option next_comment
comment 'character devices'

bool 'Zilog serial support' CONFIG_SUN_ZS n
@@ -114,6 +121,7 @@

bool 'Sun Audio support' CONFIG_SUN_AUDIO n

+mainmenu_option next_comment
comment 'Kernel hacking'

bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
diff -Nru linux-1.3.27/scripts/Configure linux/scripts/Configure
--- linux-1.3.27/scripts/Configure Sat Sep 9 07:19:23 1995
+++ linux/scripts/Configure Mon Sep 18 07:35:24 1995
@@ -16,6 +16,10 @@
#
# 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.
+#

#
# Make sure we're really running bash.
@@ -29,6 +33,16 @@
# 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 () {
+ :
+}

#
# readln reads a line into $ans.
diff -Nru linux-1.3.27/scripts/Configure.menu linux/scripts/Configure.menu
--- linux-1.3.27/scripts/Configure.menu Thu Jan 1 01:00:00 1970
+++ linux/scripts/Configure.menu Mon Sep 18 07:34:54 1995
@@ -0,0 +1,582 @@
+#! /bin/sh
+#
+# Configure.menu - This script can be used to configure the linux kernel.
+# version 0.2
+# Copyright (C) 1995 Bernhard Kaindl (e-mail: bkaindl@ping.at)
+# Address of author: Tallak 95
+# 8103 Rein - Austria
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# The same disclaimers as for the linux kernel v1.3.0 apply, see COPYING.
+#
+# It was inspired by other scripts, by the charm to actually do it
+# and to prevent to only dream of it.
+#
+# It is derived from the Configure script of linux-1.3.24 with the
+# tristate extensions and it's not designed to work with prior kernels.
+# Also tested with pre-1.3.28 for configuring the sound driver as a module.
+#
+# comments have been left out from this version, for now look at Configure
+# for explanation of the simpler functions used here.
+#
+PROGRAM=$0
+#
+# This must be here for the sparc, they make 'echo "....." >>$CONFIG'!
+#
+CONFIG=.tmpconfig
+CONFIG_H=.tmpconfig.h
+#
+if [ "$1" = x ];then
+ set -x
+ shift
+fi
+if [ "$1" = f ];then
+ fast=t
+ shift
+else
+ fast=
+fi
+if [ "$1" = d ];then
+ default=t
+ shift
+else
+ default=
+fi
+#
+# Make sure we're really running bash.
+#
+[ -z "$BASH" ] && { echo "Configure.menu requires bash" 1>&2; exit 1; }
+
+#
+# Disable pathname expansion and remember function commands.
+#
+set -f -h
+
+CONFIG_IN=./config.in
+if [ "$1" ] ; then
+ CONFIG_IN=$1
+fi
+
+if [ -z "$default" ]; then
+if [ -f .config ] ; then
+ echo "Loading .config"
+ . .config
+ sed -e 's/# \(.*\) is not.*/\1=n/' <.config >/tmp/conf.$$
+ . /tmp/conf.$$
+ rm /tmp/conf.$$
+fi
+fi
+
+if [ -z "$fast" ]; then
+#
+# mmo means "mainmenu_option"
+#
+mmo_num=0
+next_comment_is_option=nil
+comment=nil
+#
+# Functions for interpreting kconf-config.in.tmp
+#
+# ---> DEFINE STAGE 2 <---
+#
+function mainmenu_name () {
+ echo "mainmenu_name '\n$*\n'"
+}
+function comment () {
+ if test $next_comment_is_option = true; then
+ next_comment_is_option=false
+ comment=nil
+ mainmenu_option "$1"
+ return
+ else
+ comment="'$1'"
+ fi
+ echo "comment $mmo_num $mmo_setting_num '$1'"
+}
+function mainmenu_option () {
+ case "$1" in
+ next_comment)
+ next_comment_is_option=true
+ return
+ ;;
+ *)
+ name="'$1'"
+ ;;
+ esac
+ mmo_num=$[ $mmo_num + 1 ]
+ mmo_setting_num=0
+ echo -n .>&2
+ echo "option $mmo_num $name"
+ last_option_num=$mmo_num
+}
+function bool () {
+ eval def=\$\{$2:-$3}
+ mmo_setting_num=$[ $mmo_setting_num + 1 ]
+ echo setting $mmo_num $mmo_setting_num bool "'$1'" $2 $def
+ eval "$2=$def"
+}
+function tristate () {
+ eval def=\$\{$2:-$3}
+ mmo_setting_num=$[ $mmo_setting_num + 1 ]
+ echo setting $mmo_num $mmo_setting_num tristate "'$1'" $2 $def
+ eval "$2=$def"
+}
+function choice () {
+ eval def=\$\{$2:-$3}
+ mmo_setting_num=$[ $mmo_setting_num + 1 ]
+ # This must implement multi-line-arguments or not ?
+ echo setting $mmo_num $mmo_setting_num choice "'$1'" $2 $def
+ eval "$2=$def"
+}
+function int () {
+ eval def=\$\{$2:-$3}
+ mmo_setting_num=$[ $mmo_setting_num + 1 ]
+ echo setting $mmo_num $mmo_setting_num int "'$1'" $2 $def
+ eval "$2=$def"
+}
+function do_make () {
+ mmo_setting_num=$[ $mmo_setting_num + 1 ]
+ echo do_make $mmo_num $mmo_setting_num "$*"
+}
+
+function menu_if () {
+ echo "if [ "$*" ] ; then"
+}
+function menu_else () {
+ echo "else"
+}
+function menu_fi () {
+ echo "fi"
+}
+#
+# ---> DEFINE AND EXECUTE STAGE 1 <---
+#
+echo > kmenu-config.in.tmp
+sed "
+ s/^[ ]*if[ ][ ]*\[/menu_if '/
+ s/\][ ]*;[ ]*then[ ]*$/'/
+ s/^[ ]*else[ ]*$/menu_else/
+ s/^[ ]*fi[ ]*$/menu_fi/
+" $CONFIG_IN >> kmenu-config.in.tmp
+echo "\
+menu_if '\"\$CONFIG_SOUND\" -a \"\$CONFIG_SOUND\" != \"n\"'
+ mainmenu_option 'Configure sound driver'
+ do_make -C drivers/sound config
+ echo check_sound_config \$mmo_num
+menu_fi
+echo display_other_choices
+" >> kmenu-config.in.tmp
+#
+# ---> EXECUTE STAGE 2 GENERATED BY EXECUTING STAGE 1 <---
+#
+echo -n "Please wait, building menus"
+. kmenu-config.in.tmp >kmenu-config.dat
+echo
+fi # -z "$fast"
+#
+# ---> DEFINES FOR STAGE 3 <---
+#
+# Functions for helping to interpret kmenu-config.dat
+#
+function readln () {
+ echo -n "$1"
+ read ans || exit 1
+ [ -z "$ans" ] && ans=$2
+}
+function bool () {
+ case $3 in
+ y) defprompt=Y/n ;;
+ n) defprompt=N/y ;;
+ esac
+ ans=
+ while [ "$ans" != y -a "$ans" != n ]; do
+ readln "$1 ($2) [$defprompt] " $3
+ done
+ eval $2=$ans
+}
+function tristate () {
+ case $3 in
+ y) defprompt=Y/m/n ;;
+ m) defprompt=M/n/y ;;
+ n) defprompt=N/y/m ;;
+ esac
+ ans=
+ while [ "$ans" != "y" -a "$ans" != "n" -a "$ans" != "m" ]; do
+ readln "$1 ($2) [$defprompt] " $3
+ done
+ eval $2=$ans
+}
+function int () {
+ ans=x
+ while [ $[$ans+0] != "$ans" ]; do
+ readln "$1 ($2) [$3] " $3
+ done
+ eval $2=$ans
+}
+function choice () {
+ echo "choice is not yet implemented."
+}
+#
+# Functions for direct interpretation of kmenu-config.dat
+#
+function setting () {
+ case $action in
+ set)
+ eval $3=$4
+ ;;
+ view)
+ if [ $1 = $option_num ]; then
+ screen_lines=$[screen_lines+1]
+ if [ "$raw" ]; then
+ echo "$2: $5 = $6"
+ else
+ case $6 in
+ y) menu_symbol=Y ;;
+ n) menu_symbol=" " ;;
+ m) menu_symbol=M ;;
+ *) menu_symbol=$6 ;;
+ esac
+ echo -e "$2:\t[$menu_symbol] $4"
+ fi
+ last_setting_num=$2
+ fi
+ ;;
+ change)
+ if [ $1 = $option_num -a $2 = $setting_num ]; then
+ #
+ # Self-modifying part:
+ #
+ eval $3 "'$4'" $5 $6
+ sed '/^setting '$1' '$2' /s/'$6'$/'"$ans"'/' \
+ kmenu-config.dat > kmenu-config.dat.tmp
+ mv kmenu-config.dat.tmp kmenu-config.dat
+ action=changed
+ fi
+ ;;
+ showmain|changed)
+ :
+ ;;
+ *)
+ echo "action $action not known."
+ ;;
+ esac
+}
+function do_make () {
+ if [ $option_num = $1 ]; then
+ case $action in
+ view)
+ shift 2
+ echo "${MAKE:-make} $*"
+ ${MAKE:-make} $*
+ echo -n "Press <Return> to continue..."
+ read a
+ action=redisplay
+ ;;
+ *)
+ echo "action $action not known."
+ ;;
+ esac
+ fi
+}
+function check_sound_config () {
+ if test $action = showmain -a ! -e drivers/sound/local.h; then
+ echo -e "\
+\tSound is enabled, but not configured. Use this option to configure it."
+ elif test $action = view -a ! -e drivers/sound/local.h; then
+ echo -e "
+Note:\t Use mainmenu option $1 to configure the sound driver."
+ fi
+}
+function display_other_choices () {
+ case $action in
+ showmain)
+ echo
+ echo -e "w:\twrite kernel setup to disk and exit"
+ echo -e "l:\tload setup from a file saved by \`s'"
+ echo -e "s:\tsave setup to a file for later use"
+ echo -e "q:\tquit without saving changes"
+ echo
+ ;;
+ view)
+ echo
+ echo -e "b:\t back to the main menu"
+ echo
+ ;;
+ esac
+}
+function menu_ask () {
+ echo -n "Enter "
+ while :
+ do
+ echo "a option, [wlsq] or \`r' to redisplay the menu."
+ echo -n "option: "
+ read opt || exit 1
+ case "$opt" in
+ b) action=showmain
+ option_num=0
+ return
+ ;;
+ r) return
+ ;;
+ s)
+ savedir=${TOPDIR:-/usr/src/linux}/configs
+ def=last.set
+ readln "filename(dir=$savedir) [$def] " $def
+ savepath="$savedir/$ans"
+ ans=
+ while [ "$ans" != y -a "$ans" != n ]; do
+ readln \
+ "save setup to $savepath ? [n] " n
+ done
+ if [ "$ans" = y ]; then
+ test -d "$savedir" || mkdir "$savedir"
+ set|sed -n '
+ /^CONFIG_/p
+ /^NR_FTAPE_BUFFERS/p'>$savepath
+ fi
+ return
+ ;;
+ l)
+ savedir=${TOPDIR:-/usr/src/linux}/configs
+ def=last.set
+ while :
+ do
+ readln \
+ "filename(dir=$savedir) [$def] " $def
+ savepath="$savedir/$ans"
+ if test -e $savepath; then
+ break
+ else
+ echo "$savepath doesn't exist."
+ fi
+ done
+ ans=
+ while [ "$ans" != y -a "$ans" != n ]; do
+ readln \
+ "load setup from $savepath ? [n] " n
+ done
+ if [ "$ans" = y ]; then
+ set -a
+ . $savepath
+ set +a
+ exec $PROGRAM d $CONFIG_IN
+ fi
+ return
+ ;;
+ w)
+ ans=
+ while [ "$ans" != y -a "$ans" != n ]; do
+ readln \
+ "write new setup and quit ? [n] " n
+ done
+ if [ "$ans" = y ]; then
+ exit_menu=y
+ WriteConfig=true
+ fi
+ return
+ ;;
+ q)
+ ans=
+ while [ "$ans" != y -a "$ans" != n ]; do
+ readln \
+ "really quit without saving ? [n] " n
+ done
+ if [ "$ans" = y ]; then
+ exit_menu=y
+ WriteConfig=false
+ fi
+ return
+ ;;
+ esac
+ [ "$opt" -o "$opt" = 0 ] || opt=x
+ if [ "$opt" != "${opt%[^0-9]*}" ]; then
+ echo "Invalid input, try again."
+ elif [ $action = showmain -a $opt -le $last_option_num ];then
+ option_num=$opt
+ action=view
+ return
+ elif [ $action = view -a $opt -le $last_setting_num ]; then
+ action=change
+ setting_num=$opt
+ return
+ else
+ echo "Wrong option, try again."
+ fi
+ done
+}
+function mainmenu_name () {
+ if [ $action = showmain ]; then
+ echo -e "$*"
+ screen_lines=1
+ else
+ screen_lines=0
+ fi
+}
+function comment () {
+ if test $action = view -a $1 = $option_num; then
+ echo -e '\t '$3
+ screen_lines=$[screen_lines+1]
+ fi
+}
+function option () {
+ case $action in
+ showmain)
+ echo -e "$1:\t$2"
+ last_option_num=$1
+ ;;
+ view)
+ if [ "$1" = "$option_num" ]; then
+ echo -e "\nMenu:\t$2\n"
+ fi
+ ;;
+ set|change|changed)
+ :
+ ;;
+ *)
+ echo "action $action not known."
+ ;;
+ esac
+}
+#
+# ---> THIS LOOP DRIVES STAGE 3 GENERATED BY EXECUTING STAGE 2 <---
+#
+# This drives the user interface.
+#
+exit_menu=
+action=showmain
+option_num=0
+while [ -z "$exit_menu" ]
+do
+ . kmenu-config.dat
+ case $action in
+ change)
+ echo "\
+You can't change this option now, it's deactivated by an other option."
+ action=view
+ ;;
+ changed)
+ action=view
+ . kmenu-config.dat
+ ;;
+ redisplay)
+ option_num=0
+ action=showmain
+ . kmenu-config.dat
+ ;;
+ esac
+ menu_ask
+done
+if test $WriteConfig = true
+then
+#
+# And now, stage 4:
+#
+# It is generated by an echo and executed by a subshell to cleanly
+# generate the output files. This is done in a pipeline, no extra temp files
+# were used to generate itr., Also it's much simpler as stage 3.
+#
+echo '
+#
+# ---> DEFINE STAGE 4 <---
+#
+
+#
+# Disable pathname expansion and remember function commands.
+#
+set -f -h
+
+function comment () {
+ echo -e >&4 "/*\n * $3\n */"
+ echo -e >&3 "#\n# $3\n#"
+}
+function bool () {
+ case "$2" in
+ y) echo >&4 "#define $1 1"; echo >&3 $1=y ;;
+ m) echo >&4 "#undef $1"; echo >&3 $1=m ;;
+ n) echo >&4 "#undef $1"; echo >&3 "# $1 is not set" ;;
+ esac
+ eval $1=$2
+}
+function tristate () {
+ bool $*
+}
+function int () {
+ echo >&4 "#define $1 ($2)"
+ echo >&3 $1=$2
+ eval $1=$2
+}
+function choice () {
+ # Not yet implemented.
+ #define_bool "$val" "y"
+ :
+}
+function check_sound_config () {
+ if ! test -e drivers/sound/local.h; then
+ echo "
+Sound is enabled but not configured. Possible ways to configure it:
+1. use \`make [menu]config'"'"'
+2. use the shell: cd drivers/sound;make config
+3. start make, you will be asked for it during compilation"
+ fi
+}
+function display_other_choices () {
+ :
+}
+function do_make () {
+ :
+}
+function option () {
+ comment x "$@"
+}
+function mainmenu_name () {
+ :
+}
+function setting () {
+ eval $3 $5 $6
+}
+
+#
+# ---> USE DATABASE OF STAGE 3 TO EXECUTE STAGE 4 <---
+#
+
+trap "rm -f .tmpconfig .tmpconfig.h ; exit 1" 1 2
+
+#
+# create and open the output files:
+#
+exec 3>'$CONFIG' 4>'$CONFIG_H'
+
+echo >&3 "#
+# Automatically generated by Configure.menu, do not edit !
+#"
+echo >&4 "/*
+ * Automatically generated by Configure.menu, do not edit !
+ */"
+
+. kmenu-config.dat
+
+#
+# close the output files:
+#
+exec 3>&- 4>&-
+
+rm -f .config.old
+if [ -f .config ]; then
+ mv .config .config.old
+fi
+mv '$CONFIG' .config
+mv '$CONFIG_H' include/linux/autoconf.h'|$BASH
+#
+# THE END
+#
+echo
+echo "The linux kernel is now hopefully configured for your setup."
+echo "Check the top-level Makefile for additional configuration,"
+echo "and do a 'make dep ; make clean' if you want to be sure all"
+echo "the files are correctly re-made"
+echo
+fi
+exit 0