root/scripts/Menuconfig

/* [previous][next][first][last][top][bottom][index][help] */
#! /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.
#
# Please send comments / questions / bug fixes to roadcapw@cfw.com
#
#----------------------------------------------------------------------------


#
# 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
#
set -h

#
# Extract available help for an option from Configure.help
# and send it to standard output.
#
# Most of this function was borrowed from the original kernel
# Configure script.
#
function extract_help () {
  if [ -f Documentation/Configure.help ]
  then
     #first escape regexp special characters in the argument:
     var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
     #now pick out the right help text:
     text=$(sed -n "/^$var[     ]*\$/,\${
                        /^$var[         ]*\$/d
                        /^#.*/d
                        /^[     ]*\$/q
                        p
                    }" Documentation/Configure.help)

     if [ -z "$text" ]
     then
          echo "There is no help available for this kernel option."
     else
          echo "$text"
     fi
  else
         echo "There is no help available for this kernel option."
  fi
}

#
# Activate a help dialog.
#
function help () {
        if extract_help $1 >help.out
        then
                $DIALOG --backtitle "$backtitle" --title "$2"\
                        --textbox help.out $LINES $COLS
        else
                $DIALOG --backtitle "$backtitle" \
                        --textbox help.out $LINES $COLS
        fi
        rm help.out
}

#
# Show the README file.
#
function show_readme() {
        $DIALOG --backtitle "$backtitle" \
                --textbox scripts/README.Menuconfig $LINES $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' \
                        $LINES $COLS $((LINES-10)) \
                        '$default' " >MCmenu
        >MCradiolists
}

#
# Additional comments
#
function comment () {
        comment_ctr=$[ comment_ctr + 1 ]
        echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
}

#
# Don't need this yet, but we don't want to puke either.
#
function define_bool () {
        :       
}

#
# Add a submenu option to the menu currently under construction.
#
function submenu () {
        echo -ne "'activate_menu $2' '$1  --->' " >>MCmenu
}

#
# Create a menu entry to handle the traditional sound configuration.
#
function soundcfg () {
        echo -ne "'l_soundcfg' "\
                 "'Old configuration script "\
                 "(For: SM Wave, PSS & AudioTrix Pro) -->' " >>MCmenu
}

#
# Startup the traditional sound configuration program.
#
function l_soundcfg () {
        clear
        $MAKE -C drivers/sound config
}


#
# Create a boolean (Yes/No) function for our current menu
# which calls our local bool function.
#
function bool () {
        eval $2=\${$2:-'n'}  x=\$$2

        case $x in
        y|m) yes='ON' no='OFF' flag="*"
           ;;
        n) yes='OFF' no='ON' flag=" "
           ;;
        esac

        echo -ne "'$2' '($flag) $1' " >>MCmenu

        echo -e "function $2 () { l_bool '$1' '$yes' '$no' '$2' }\n" \
                >>MCradiolists
}

#
# Handle a boolean (Yes/No) option.
#
function l_bool () {
        while true
        do
                $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 12 70 2 \
                        'y' 'Yes' $2 'n' 'No' $3 2>MCdialog.out

                case "$?" in
                0) eval $4=`cat MCdialog.out`
                   break ;;

                1) help "$4" "$1" ;;

                *) break ;;
                esac
        done
}

#
# Same as bool() except options are (Module/No)
#
function mod_bool () {
        eval $2=\${$2:-'n'}  x=\$$2

        case $x in
        m) module='ON'  no='OFF' flag='M'
           ;;
        *) module='OFF' no='ON'  flag=' '
           ;;
        esac

        echo -ne "'$2' '($flag) $1' " >>MCmenu

        echo -e "function $2 () { l_mod_bool '$1' '$module' '$no' '$2' }\n" \
                >>MCradiolists
}

#
# Same as l_bool() except options are (Module/No)
#
function l_mod_bool() {
        while true
        do
                $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 12 70 2 \
                        'm' 'Module' $2 'n' 'No' $3 2>MCdialog.out

                case "$?" in
                0) eval $4=`cat MCdialog.out`
                   break ;;

                1) help "$4" "$1" ;;

                *) break ;;
                esac
                        
        done
}

#
# 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
                eval $2=\${$2:-'n'}  x=\$$2
        
                case $x in
                y) yes='ON'  no='OFF' module='OFF' flag="*"
                ;;
                m) yes='OFF' no='OFF' module='ON' flag="M"
                ;;
                *) yes='OFF' no='ON'  module='OFF' flag=" "
                ;;
                esac
        
                echo -ne "'$2' '($flag) $1' " >>MCmenu
        
                echo -e "
                function $2 () { \
                        l_tristate '$1' '$yes' '$no' '$module' '$2'
                }"  >>MCradiolists
        fi
}

#
# Handle a tristate (Yes/No/Module) option.
#
function l_tristate () {
        while true
        do
                $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 13 70 3 \
                        'y' 'Yes' $2 'n' 'No' $3 'm' 'Module' $4 \
                        2>MCdialog.out

                case "$?" in
                0) eval $5=`cat MCdialog.out`
                   break ;;

                1) help "$5" "$1" ;;

                *) break ;;
                esac
        done
}

#
# 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 () {
        if [ "$CONFIG_MODULES" != "y" ]
        then
                bool "$1" "$2"
        else
                if  eval [ "_$3" != "_m" ]
                then
                        tristate "$1" "$2" $3
                else
                        mod_bool "$1" "$2"
                fi
        fi
}

#
# Add a menu item which will call our local int function.
# 
function int () {
        eval $2=\${$2:-"$3"} x=\$$2

        echo -ne "'$2' '($x) $1' " >>MCmenu

        echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>MCradiolists
}

#
# 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" \
                        15 55 "$4" 2>MCdialog.out
                then
                        answer="`cat MCdialog.out`"
                        answer="${answer:-$3}"

                        if expr $answer : '0$\|-?[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
}


#
# Add a menu item which will call our local int function.
# 
function hex () {
        eval $2=\${$2:-"$3"} x=\${$2##*[x,X]}

        echo -ne "'$2' '($x) $1' " >>MCmenu

        echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>MCradiolists
}

#
# Create a dialog for entering a hexidecimal into a kernel option.
#
function l_hex () {
        while true
        do
                if $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --inputbox "$inputbox_instructions_hex" \
                        15 55 "$4" 2>MCdialog.out
                then
                        answer="`cat MCdialog.out`"
                        answer="${answer:-$3}"
                        answer="${answer##*[x,X]}"

                        if expr $answer : '[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
}

#
# Add a menu item which will call our local One-of-Many choice list.
#
function choice () {
        #
        # Need to remember params cause the'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
        }\n" >>MCradiolists
}


function l_choice () {
        #
        # Need to remember params cause the're gonna get reset.
        #
        title="$1"
        choices="$2"
        current="$3"

        #
        # Scan current value of choices and set radiolist switches.
        #
        list=
        set -- $choices
        firstchoice=$2
        while [ -n "$2" ]
        do
                case "$1" in
                "$current")     list="$list $2 $1 ON "  ;;
                *)              list="$list $2 $1 OFF " ;;
                esac
                        
                shift ; shift
        done

        while true
        do
                if $DIALOG --title "$title" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" \
                        22 70 11 $list 2>MCdialog.out
                then
                        choice=`cat MCdialog.out`
                        break
                fi

                help "$firstchoice" "$title"
        done

        #
        # Now set the boolean value of each option base 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
}


#
# A faster awk based recursive parser. (I hope)
#
function parser1 () {
awk '
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

                        printf( "function MCmenu%s () {\n"\
                                "default=$1\n"\
                                "menu_name %s\n",\
                                 menu_no, $0) >"MCmenu"menu_no

                        parser(ifile, "MCmenu"menu_no)
                }
                else if ($1 ~ "endmenu") {
                        printf("}\n") >>menu
                        return
                } 
                else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
                        printf("") >>menu
                }
                else if ($1 == "source") {
                        # Yuk!  Blah!  Phooey!
                        if ($2 ~ "drivers/sound") {
                                printf("soundcfg\n") >>menu
                        }

                        parser($2,menu)
                }
                else {
                        print >>menu
                }
        }
}'
}

#
# Secondary parser for single menu mode.
#
function parser2 () {
awk '
BEGIN {
        parser("'$CONFIG_IN'","MCmenu0")
}

function parser(ifile,menu) {

        while (getline <ifile) {
                if ($1 ~ /mainmenu_option|endmenu/) {
                        printf("") >>menu
                } 
                else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
                        printf("") >>menu
                }
                else if ($1 == "source") {
                        if ($2 ~ "drivers/sound") {
                                printf("soundcfg\n") >>menu
                        }
                        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 "}" >>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 disgard them.
        #
        for i in MCmenu*
        do
                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 () {

        while true
        do
                comment_ctr=0
                $1 "$default"           #Create the radiolists and dialog cmd
                . MCradiolists          #Read in the dialog functions.

                . MCmenu 2>MCdialog.out #Activate this menu

                case "$?" in
                0)
                        defaults="`cat MCdialog.out`$defaults"  #psuedo stack
                        . MCdialog.out
                        default="${defaults%%*}" defaults="${defaults#*}"
                        ;;
                2)      
                        echo >>MCdialog.out
                        read selection <MCdialog.out
                        default="${selection%% *}"

                        case "$selection" in
                        *"-->"*) show_readme ;;
                        *)       eval help $selection ;;
                        esac
                        ;;
                255|1)
                        break
                        ;;
                esac
        done
}

#
# Just what it says.
#
save_configuration () {
        ${DIALOG} --backtitle "$backtitle" \
                  --infobox "Saving your new kernel configuration..."  3 43

        #
        # Now, let's redefine the configuration functions for final
        # output to the config files.
        #
        function bool () {
                eval define_bool "$2" "\${$2:-n}"
        }

        function tristate () {
                eval define_bool "$2" "\${$2:-n}"
        }

        function dep_tristate () {
                eval x=\${$2:-n}

                if eval [ "_$3" = "_m" ]
                then
                        if [ "$x" = "y" ]
                        then
                                x="m"
                        fi
                fi

                define_bool "$2" "$x"
        }

        function int () {
                eval x=\${$2:-"$3"}
                echo "$2=$x"            >>$CONFIG
                echo "#define $2 ($x)"  >>$CONFIG_H
        }

        function hex () {
                eval x=\${$2:-"$3"}
                echo "$2=$x"                     >>$CONFIG
                echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
        }

        function define_bool () {
                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
                        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=

                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}

                #
                # Then extract the actual option from the list of choices.
                #
                current=${choices#*$current} ; set $current

                define_bool "$1" "y"
        }

        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
        }

        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

        MAKE=:  #To prevent sound Makefile from running.
        
        if . $CONFIG_IN >>.menuconfig.log 2>&1
        then
                #
                # Create the sound driver's config files for cards
                # Which are compatible with the new config method.
                #
                if [ "_$CONFIG_TRIX"   != "_y" -a\
                     "_$CONFIG_PSS"    != "_y" -a\
                     "_$CONFIG_SMWAVE" != "_y"    ]
                then
                        make -C drivers/sound kernelconfig >>.menuconfig.log 2>&1
                fi

                if [ -f .config ]
                then
                        rm -f .config.old
                        mv .config .config.old
                fi
                mv .tmpconfig .config
                mv .tmpconfig.h include/linux/autoconf.h
                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
}

x=`stty -a`
case $x in
*\ rows\ *\;*)
        LINES=${x##*rows}    LINES=${LINES%%;*} LINES=$((${LINES:-25}-4))
        COLS=${x##*columns}  COLS=${COLS%%;*}   COLS=$((${COLS:-80}-5))
        ;;
*)
        LINES=21
        COLS=75
        ;;
esac
        

menu_instructions="\
Arrow keys navigate the menu.  \
Highlighted letters are hotkeys.  \
Select an item with <Space Bar> or <Enter>.  \
When finished press <Esc><Esc> or <X>.  \
A (*) marks an option to be compiled into the kernel.  \
An (M) marks an option to be compiled as a module."

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 <H> for additional information about this option."

inputbox_instructions_int="\
Please enter a decimal value between 1 and 9999. \
Fractions will not be accepted.  \
Use the <TAB> key to move from the input field to buttons below it."

inputbox_instructions_hex="\
Please enter a hexidecimal value. \
Use the <TAB> key to move from the input field to buttons below it."

backtitle="Linux Kernel Configuration"

DIALOG="./scripts/lxdialog/lxdialog"

kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"

trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15

#
# Locate default files.
#
DEFAULT=""
if [ "$1" = "-d" ] ; then
        DEFAULT="-d"
        shift
fi

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 "#"
  echo "# Using defaults found in" $DEFAULTS
  echo "#"
  . $DEFAULTS
else
  echo "#"
  echo "# No defaults found"
  echo "#"
fi

# Fresh new log.
>.menuconfig.log


$DIALOG --backtitle "$backtitle" \
        --infobox "Preparing configuration scripts..." 3 40

#
# Check kernel version of previous menuconfig build.
# If it's different then we should tell the sound driver
# to rebuild it's Config.in file.
#
rebuildsound=TRUE
if [ -e .menuconfig ]
then
        read x <.menuconfig
        if [ "$x" = "# $kernel_version" ]
        then
                rebuildsound=
        fi
fi

if [ "$rebuildsound" ]
then
        # Activate the Linux compatible sound configuration.
        # This may not work for all sound cards.  (See sound docs)
        #
        make -C drivers/sound mkscript >>.menuconfig.log 2>&1

        echo "# $kernel_version" >.menuconfig
fi

#
# Read config.in files and parse them into one shell function per menu.
#
parse_config_files $CONFIG_IN

#
# 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

        clear
        cat <<EOM


The linux kernel is now hopefully configured for your setup.
Check the top-level Makefile for additional configuration,
and do a 'make dep ; make clean' if you want to be sure all
the files are correctly re-made.

EOM
else
        clear
        echo -e "Your kernel configuration changes were NOT saved.\n"
fi


exit 0


/* [previous][next][first][last][top][bottom][index][help] */