#! /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).

#
# 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 () {
	:
}

#
# Read the langfile and get the info there:
#
function read_langfile () {
	langfile=$1
	lang_choices=`sed 's/=.*//' $langfile`
	rm -f .MClangfile.tmp
	sed 's/=/_FILE=/' $langfile >.MClangfile.tmp
	source .MClangfile.tmp
	rm -f .MClangfile.tmp
}


#
# Read the langfile and get the info there:
#
function set_helpfile () {
	helpfile=Documentation/Configure.help
	set -- $lang_choices
	for lang_choice in $lang_choices
	do
		if eval [ "_\$$lang_choice" = "_y" ]
		then
			#eval echo "\$${lang_choice}_FILE"
			eval helpfile="\$${lang_choice}_FILE"
		fi
	done 
	#echo $helpfile
}

#
# help creates a help text and shows it through a pager.
#
#       help variable
#
function help () {
	extract_help $1 | ${PAGER:-more}
}

#
# Create a help text by extracting available help for an option from
# Configure.help and send it to standard output.
#
function extract_help () {

  #some initialisation:
  filefound=
  text=

  #escape regexp special characters in the argument:
  var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')

  #now pick out the right help text:
  #helpfile=Documentation/Configure.de.help
  set_helpfile

     if [ -r $helpfile ]
     then
        filefound=y
        text=$(sed -n "/^$var[ 	]*\$/,\${
                        /^$var[ 	]*\$/c\\
${var}:\\

                        /^#/b
                        /^[^ 	]/q
                        s/^  //
                        p
                    }" $helpfile)
     fi

  # Fallback-File:
  if [ -z "$text" ]
  then
     helpfile=Documentation/Configure.help
     if [ -r $helpfile ]
     then
        filefound=y
        text=$(sed -n "/^$var[ 	]*\$/,\${
                        /^$var[ 	]*\$/c\\
${var}:\\

                        /^#/b
                        /^[^ 	]/q
                        s/^  //
                        p
                    }" $helpfile)
     fi
  fi

  if [ -z "$text" ]
  then
     if [ -z "$filefound" ]
     then
        echo "\
No help available - unable to open file Documentation/Configure.help.
This file should have come with your kernel."
	return 1
     else
	 echo "There is no help available for this kernel option."
     fi
  else
     echo "$text"
     echo
  fi
}


#
# readln reads a line into $ans.
#
#	readln prompt default oldval
#
function readln () {
	if [ "$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
}

#
# menucomment calls comment (is used only for marking menus, which is not
# supported here and for translating the texts to foreign langugages, which
# may be implemented here.
#
#	menucomment MENU_KEY 'xxx'
# 
function menucomment () {
	comment "$2"
}

#
# 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 () {
	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'}
	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'}
	  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_bool "$2" "y"
			      break ;;
	      [nN] | [nN]o )  define_bool "$2" "n"
			      break ;;
	      [mM] )          define_bool "$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_bool "$var" "n"
	      return
	      ;;
	    m)
	      need_module=1
	      ;;
	  esac
	  shift
	done

	if [ $need_module = 1 ]; then
	   if [ "$CONFIG_MODULES" = "y" ]; then
		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_bool "$var" "n"
				      break ;;
		      [mM] )          define_bool "$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
}

#
# 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 [min max]
#
function int () {
	old=$(eval echo "\${$2}")
	def=${old:-$3}
	if [ $# -gt 3 ]; then
	  min=$4
	else
	  min=-10000000    # !!
	fi
	if [ $# -gt 4 ]; then
	  max=$5
	else
	  max=10000000     # !!
	fi
	while :; do
	  readln "$1 ($2) [$def] " "$def" "$old"
	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; 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]}
	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}
	readln "$1 ($2) [$def] " "$def" "$old"
	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

	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"* )
					if [ "$name" = "$ans" ]; then
						val="$2"
						break	# stop on exact match
					fi
					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
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

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
  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$
  . .config-is-not.$$
  rm .config-is-not.$$
else
  echo "#"
  echo "# No defaults found"
  echo "#"
fi

# read_langfile "Documentation/lang/languages.cfg"

. $CONFIG_IN

rm -f .config.old
if [ -f .config ]; then
	mv .config .config.old
fi

mv .tmpconfig .config
mv .tmpconfig.h autoconf.h

echo
echo "The Alpha Linux Miniloader is now hopefully configured for your setup."
echo "Before building MILO you may need to do a 'make clean'."
echo

exit 0
