#! /bin/sh

if test $# -eq 1 -a "$1" = builddist; then
  BUILDDIST=true
else
  BUILDDIST=false
fi

cat <<GAZONK
#
# WELCOME TO KLIC SYSTEM CONFIGURAION SCRIPT
#
#  Copyright 1994 Institute for New Generation Computer Technology
#  Read COPYRIGHT for detailed information
#
# In this script, I'll ask you for several options you can make.
# Default values are presented in brackets as in [default].
# If the default is OK, simply hit CR.
# Otherwise, type in whatever is your option.
# When you want to specify nothing, type in "none".
#

GAZONK

: Find how to suppress newline after echo
if ( echo "test line\c"; echo " ") | grep c >/dev/null 2>/dev/null ; then
    n='-n'
    c=''
else
    n=''
    c='\c'
fi

: Define some handy functions

clean_up_config () {
  rm -f nmout.tmp nmout.list nmout.all testprefix 2>/dev/null
}

give_up_config () {
    echo " "
    for message do
	echo "!!! $message !!!"
    done
    clean_up_config
    echo "Aborting KLIC configuration script"
    echo ' '
    exit 1
}

ask_yes_or_no () {
    default=$1
    default_value=$2
    echo $n " (yes or no)"$c
    while true ; do
	echo $n " [$default] "$c
	read ans
	case $ans in
	'') return $default_value;;
	yes) return 0;;
	no) return 1;;
	esac
	echo $n "Please input yes or no"$c
    done
}

ask_with_default () {
    message=$1
    macroname=$2
    eval default=\$$macroname
    echo $n "Which $message would like to use? [$default] "$c
    read ans
    case $ans in
    none) ans='';;
    '') ans=$default ;;
    esac
    eval $macroname=\$ans
}

locate_file () {
file=$1
shift
kind=$1
shift
for dir in $*; do
    if test -$kind $dir/$file; then
	where=$dir/$file
	return 0
    fi
done
return 1
}

locate_executable () {
    file=$1
    shift
    user_path=$*
    locate_file "$file" x $user_path
    return
}

locate_directory () {
    located_dir=$1
    test -d $located_dir ||
    {
	echo $n "Cannot find $located_dir; Create it now? "$c
	if ask_yes_or_no yes 0; then
	    if mkdir $located_dir ; then
		return 0
	    else
		echo "!!! Couldn't create $located_dir !!!"
		return 1
	    fi
	else
	    return 1
	fi
    }
}

ask_additional () {
message=$1
macroname=$2
eval default=\$$macroname
case $default in
  '') default="none" ;;
esac
echo "# Default $message are: $default"
echo ' '
echo $n "Do you want to change the default? "$c
if ask_yes_or_no no 1; then
  echo ' '
  if test '$default'!=none; then
    echo $n "Do you want to delete any of them? "$c
    if ask_yes_or_no no 1; then
      echo ' '
      echo "# OK, then I'll clear the default."
      eval $macroname=\"\"
      default=
      echo "# Now there are no default $message."
      echo ' '
    fi
  fi
  echo $n "Specify additions if any: "$c
  while true; do
      read ans
      case $ans in
      '') return 0;;
      *) eval $macroname=\"\$$macroname \$ans\"
      esac
      echo $n "More? "$c
  done
fi
}

ask_executable () {
what=$1
macroname=$2
while true; do
    eval default=\$$macroname
    echo $n "Which $what do you plan to use? [$default] "$c
    read ans
    case $ans in
    '') eval result=\$$macroname;;
    *) result=$ans;;
    esac
    case $result in
    /*) {
	  if test -x $result; then
	      eval $macroname=\$result
	      return 0
	  else
	      echo !!! Can\'t find an executable file \"$result\" !!!
	  fi
	};;
    *)	{
	  if locate_executable $result $user_path; then
	      eval $macroname=\$result
	      return 0
	  else
	      echo !!! Can\'t find \"$result\" along your path !!!
	      echo ' '
	  fi
	} ;;
    esac
done
}

ask_directory () {
what=$1
macroname=$2
while true; do
    eval default=\$$macroname
    echo $n "Which $what directory do you plan to use? [$default] "$c
    read ans
    case $ans in
    '') eval result=\$$macroname;;
    *) result=$ans;;
    esac
    if locate_directory "$result"; then
        eval $macroname=\$result
	return 0
    fi
done
}

check_writable () {
what=$1
macroname=$2
eval filename=\$$macroname
if test -d $filename; then
    if test -w $filename; then
	return
    else
	echo "!!! You do not  have write access to $filename !!!"
    fi
elif test -f $filename; then
    echo "!!! $filename is not a directory"
else
    echo "!!! Directory $filename does not exist !!!"
fi
ask_directory "$what" $macroname
}

if test -f Makefile; then
cat <<GAZONK
# I found Makefile in this directory.  This might mean that you already
# have installed the KLIC system before.

GAZONK
echo $n "May I clean-up the directory by \"make distclean\" first? "$c
if ask_yes_or_no yes 0; then
  make distclean ||
  give_up_config "Make distclean ends with non-zero return code"
  echo ' '
else
  give_up_config "OK, then I'll stop reconfiguration."
fi
fi

user_path=`echo $PATH | sed -e 's/:/ /g'`
export user_path

if $BUILDDIST; then
  cat <<GAZONK
# You specified to rebuild the distribution.
# To rebuild the distribution, an already working KL1 to C compiler (kl1cmp)
# and a KLIC database manager (klicdb) are required.

GAZONK
  KLICDIR="/usr/local/lib/klic"
  ask_directory "KLIC Library Directory" "OLDLIBDIR" || exit 1
  echo ' '
  KL1CMP="$OLDLIBDIR/kl1cmp"
  ask_executable "KL1 to C compiler (kl1cmp)" "KL1CMP" || exit 1
  echo ' '
  KLICDB="$OLDLIBDIR/klicdb"
  ask_executable "KLIC databse manager (klicdb)" "KLICDB" || exit 1
  echo ' '
else
  KL1CMP="false"
  KLICDB="false"
fi

if locate_executable "gcc" $user_path; then
    CC="gcc"
    cat <<GAZONK
# Found gcc in $where.
# I'd recommend using gcc for installing KLIC, as it's been tested
# mainly with gcc.

GAZONK
else
    CC=cc
fi

ask_executable "C compiler" "CC" || exit 1
echo ' '

case $CC in
  "gcc -pipe" | gcc)
	OPTLEVEL="2"
	DEBUGFLAGS="-g"
	UOPTFLAGS="-fomit-frame-pointer";;
  cc)	OPTLEVEL=none
	DEBUGFLAGS=""
        UOPTFLAGS="";;
  *)	OPTLEVEL=none
	DEBUGFLAGS=""
        UOPTFLAGS="";;
esac

cat <<GAZONK
# During the installation procedure, the runtime library for the KLIC system
# will be compiled using $CC.
#
# You can choose optimization and debug flags for this compilation now
# (I'll ask you default setting for compiling user programs later).

GAZONK
ask_with_default "optimization level" OPTLEVEL
ask_with_default "debug flags" DEBUGFLAGS
echo " "

cat <<GAZONK
# When KL1 programs are compiled, they are compiled into C code and then
# compiled into executable using $CC.  You can specify optimization level
# and debug flag for $CC in the command line argument for the KLIC compiler.
#
# You can here select flags that'll be only set for optimized compilation,
# that is, flags that'll be supplied only when you specified -O# when you
# run the KLIC compiler.

GAZONK
ask_with_default "additional optimization flags" UOPTFLAGS
echo " "

case $OPTLEVEL in
  "none" | "" | 0)
	OPTFLAGS=""
	KLICOPT="";;
  1|2|3|4|5|6|7|8|9)
	OPTFLAGS="-O$OPTLEVEL $UOPTFLAGS"
	KLICOPT="-O$OPTLEVEL";;
  *)	OPTFLAGS=""
	KLICOPT=""
	OPTLEVEL=0
	echo "Illegal optimization level ($OPTLEVEL); set to 0";;
esac

if locate_executable "ranlib" $user_path; then
    RANLIB=ranlib
else
    RANLIB=true
    cat <<GAZONK
# I couldn't find "ranlib" along your path.
# Use "true" instead if your system doesn't need running ranlib.

GAZONK
    ask_executable "library indexer" "RANLIB" || exit 1
    echo ' '
fi

if locate_executable "make" $user_path; then
    MAKE=make
else
    MAKE=""
    cat <<GAZONK
# I couldn't find "make" along your path.

GAZONK
    ask_executable "make" "MAKE" || exit 1
    echo ' '
fi

INSTALL="/bin/cp -p"
INSTDIR="/bin/mkdir -p"

cat <<GAZONK
# For KLIC to support asynchronous stream I/O, the system should 
# deliver signals such as SIGIO or SIGPOLL when I/O becomes possible.
# However, some systems (such as Linux 1.0) does not support this.

GAZONK
echo $n "Does your system support I/O ready signals?"$c
if ask_yes_or_no yes 0; then
    ASYNCIO="#define"
else
    ASYNCIO="#undef"
fi
echo ' '

cat <<GAZONK
# The KLIC system will be installed under certain directories.
# You have to be able to write into that directory for installation.
# Also, the installed files under the directory should be visible from
# all the KLIC users (only yourself for a private installation).
#
# First, the root of the installation directory tree.

GAZONK

DIRPREFIX="/usr/local"
ask_directory "intallation root" DIRPREFIX ||
give_up_config "Coudn't determine installation root directory"

cat <<GAZONK

# By default, KLIC system will be installed in the subdirectories of
# the directory you specified ($DIRPREFIX).
# In the default setting, subdirectories used are:
#    $DIRPREFIX/bin:     for user command (klic)
#    $DIRPREFIX/lib:     for subprograms and libraries
#    $DIRPREFIX/include: for header files

GAZONK

KLICBIN=$DIRPREFIX/bin
KLICLIB=$DIRPREFIX/lib
KLICINCLUDE=$DIRPREFIX/include

echo $n  "May I use the default setting?"$c
ask_yes_or_no yes 0 ||
{
    ask_directory "user command" KLICBIN
    ask_directory "library" KLICLIB
    ask_directory "include file" KLICINCLUDE
}
check_writable "user command" KLICBIN
check_writable "library" KLICLIB
check_writable "include file" KLICINCLUDE
echo " "

LIBPATH=""
for dir in /lib /usr/lib /usr/local/lib; do
    if test -d $dir; then
	LIBPATH="$LIBPATH $dir"
    fi
done

echo "# Specify directories for library archives."
ask_additional "library directories" LIBPATH
echo ' '

INCLUDEDIR=/usr/include
while test ! -d $INCLUDEDIR; do
    echo "# I couldn't find $INCLUDEDIR"
    ask_directory "default include file directory" INCLUDEDIR
done

LIBNAMES=""
locate_file libc.a f $LIBPATH && LIBNAMES="$LIBNAMES libc"
locate_file libm.a f $LIBPATH && LIBNAMES="$LIBNAMES libm"
locate_file libelf.a f $LIBPATH && LIBNAMES="$LIBNAMES libelf"
locate_file libsocket.a f $LIBPATH && LIBNAMES="$LIBNAMES libsocket"
locate_file libnsl.a f $LIBPATH && LIBNAMES="$LIBNAMES libnsl"

echo "# Specify library archive files."
ask_additional "library archives" LIBNAMES
echo ' '

LIBFILES=''
echo $n "# Using library file(s):"$c
for lib in $LIBNAMES; do
  if locate_file $lib.a f $LIBPATH; then
    LIBFILES="$LIBFILES $where"
    echo $n " $where"$c
  else
    give_up_config "Couldn't find $lib.a in $LIBPATH"
  fi
done
echo ' '
echo ' '

LIBSWITCHES=`echo " " $LIBNAMES | sed -n -e "s/ lib/ -l/gp"`

for dir in $LIBPATH ; do
   LIBSWITCHES="$LIBSWITCHES -L$dir"
done

echo "# Specify directories for header files at KL1 program compilation."
ask_additional "include directory for compiling KLIC" KLICINCLUDE
echo ' '

USER=${USER:-unknown}
case $USER in
  unknown)
    if locate_executable "whoami" $user_path; then
	USER=`$where`
    fi
esac

locate_executable "nm" $user_path ||
give_up_config "Couldn't find "nm" along your path"

echo "# I'll make a summary of libraries for later use in analysis."
echo $n "# It may take a while."$c

rm -f nmout.all 2>/dev/null
for libfile in $LIBFILES; do
  echo $n .$c
  nm $libfile 2>/dev/null >>nmout.all
done
grep printf <nmout.all >nmout.tmp

try_sed()
{
    echo $n .$c
    sedargs=''
    for arg do
	sedargs="$sedargs -e '$arg'"
    done
    eval sed -n $sedargs <nmout.tmp >nmout.list
    grep '^printf$' nmout.list >/dev/null 2>/dev/null
    return
}

try_sed 's/^.* [ATDSI]  *[_.]*//p' 's/^.* [ATDSI] //p' ||
try_sed 's/^__*//' 's/^\([a-zA-Z_0-9$]*\).*xtern.*/\1/p' ||
try_sed '/|UNDEF/d' '/FUNC..GL/s/^.*|__*//p' ||
try_sed 's/^.* D __*//p' 's/^.* D //p' ||
try_sed 's/^_//' 's/^\([a-zA-Z_0-9]*\).*xtern.*text.*/\1/p' ||
try_sed '/|COMMON/d' '/|DATA/d' '/ file/d' 's/^\([^     ]*\).*/\1/p' ||
try_sed 's/^.*|FUNC |GLOB .*|//p' 's/^.*|FUNC |WEAK .*|//p' ||
try_sed 's/^[         ]*[0-9][0-9a-f]*[       ]*Def. Text[    ]*//p' ||
try_sed 's/^.* [AT]  *_[_.]*//p' 's/^.* [AT] //p' ||
give_up_config "nm didn't seem to work right or libraries are clobbered "

eval sed -n $sedargs <nmout.all >nmout.list

cat <<GAZONK
 done
#
# I now start testing availability of features I might use...

GAZONK

find_label ()
{
    grep "^$1\$" nmout.list >/dev/null 2>/dev/null
    return
}

if find_label nlist; then
	:
else
    echo <<GAZONK
# I need "nlist" to continue configuration, which I cannot find in:
#     $LIBFILES
# Please run configuration script again and specify appropriate library.
GAZONK
    give_up_config "nlist was not found"
fi

define="#define"
undef="#undef"

test_label()
{
    testedlabel=$1
    macroname=$2
    if find_label $testedlabel; then
	echo "     found \"$testedlabel\""
	eval $macroname=\$define
	return 0
    else
	echo "     cannot find \"$testedlabel\"; I'll try without it."
	eval $macroname=\$undef
	return 1
    fi
}

test_either()
{
    onelabel=$1
    anotherlabel=$2
    macroname=$3
    test_label $onelabel $macroname ||
    test_label $anotherlabel DUMMY ||
    give_up_config "Can't find either $onelabel or $anotherlabel"
}

test_include()
{
    file=$1
    macro=$2
    shift
    if locate_file "$file" f $INCLUDEDIR; then
	echo "     found \"$file\""
	eval $macro=\$define
	return 0
    else
	echo "     cannot find \"$file\"; I'll try without it."
	eval $macro=\$undef
	return 1
    fi
}

test_include string.h STRINGH

test_label setlinebuf SETLINEBUF
test_label lockf USELOCKF
test_label sigaction USESIG
test_label getrusage GETRUSAGE
test_either bcmp memcmp USEBCMP
test_either bcopy memcpy USEBCOPY
test_either bzero memset USEBZERO
test_either strchr index USESTRCHR
test_either usleep sleep USEUSLEEP

cat <<GAZONK

# Now I'll check whether your system prefixes some character
# to labels defined by C programs...
GAZONK

$CC -o testprefix testprefix.c $LIBSWITCHES ||
give_up_config "Couldn't compile label prefix test program"

NLIST_PREFIX_STRING=`./testprefix`
case $NLIST_PREFIX_STRING in
'') echo "# I'll use no prefixes at all." ;;
*) echo "# I'll use \"$NLIST_PREFIX_STRING\" as prefix." ;;
esac
echo ' '

echo "# Writing out config.h file."
cat <<GAZONK >config.h
/*
  Copyright 1994 Institute for New Generation Computer Technology
  Read COPYRIGHT for detailed information

  KLIC System Configuration Setting
  This file was created by KLIC configuration script.
  Date of Confuguration: `date`
  Configured by: ${USER:-unknown}
*/

/* Directories for installation */

#define KLICBIN "$KLICBIN"
#define KLICLIB "$KLICLIB"
#define KLICINCLUDE "$KLICINCLUDE"
#define KLIC_COMPILER "$KLICLIB/klic/kl1cmp"
#define KLIC_DBMAKER "$KLICLIB/klic/klicdb"

/* Laguage and program processing systems */

#define CC "$CC"
#define LD "$CC"
#define RANLIB "$RANLIB"

/* Additional CC flags for optimized compilation of KL1 programs */

#define UOPTFLAGS "$UOPTFLAGS"

/* Additional flags for LD */

#define LIBRARIES "-lklic $LIBSWITCHES"
#define LIBRARIES_T "-lklict $LIBSWITCHES"

/* String to be prefixed to C labels */
#define PREFIX_STRING "$NLIST_PREFIX_STRING"

/* Usual C macros depending on availability */

$ASYNCIO ASYNCIO
$STRINGH STRINGH
$SETLINEBUF SETLINEBUF
$USELOCKF USELOCKF
$USESIG USESIG
$GETRUSAGE GETRUSAGE
$USEBCMP USEBCMP
$USEBCOPY USEBCOPY
$USEBZERO USEBZERO
$USESTRCHR USESTRCHR
$USEUSLEEP USEUSLEEP
GAZONK
echo ' '

echo "# Writing out Makefile"
cat <<GAZONK >Makefile
# Copyright 1993, 1994 Institute for New Generation Computer Technology
# Read COPYRIGHT for detailed information
#
# Top-level Makefile for KLIC system
# This file was created by KLIC configuration script.
# Date of Confuguration: `date`
# Configured by: ${USER:-unknown}

########################################
# Directory Names
########################################

# Include file directory
KLICINCLUDE = $KLICINCLUDE

# Library directory
KLICLIB = $KLICLIB

# Executable directory
KLICBIN = $KLICBIN

########################################
# System-dependent switches
########################################

# KLIC system used for compiling the self compiler
# Only for system developers and not for normal users
KL1CMP = $KL1CMP
KLICDB = $KLICDB

# C compiler
CC = $CC
LD = $CC

# Optimization flags for compiling the runtime system by CC.
OPTLEVEL = $OPTLEVEL
OPTFLAGS = $OPTFLAGS
KLICOPT = $KLICOPT $DEBUGFLAGS
DEBUGFLAGS = $DEBUGFLAGS

# Additional CC flags for optimized compilation of KL1 programs.
UOPTFLAGS = $UOPTFLAGS

# Library search flags
LIBSWITCHES = $LIBSWITCHES

# Library archive indexer
RANLIB = $RANLIB

# Make program
MAKE = $MAKE

# Installer
INSTALL = $INSTALL
INSTDIR = $INSTDIR
INSTALLHDR = /bin/cp -p

# Prefix string put before C-defined labels
NLIST_PREFIX_STRING = "$NLIST_PREFIX_STRING"

GAZONK
cat <Makefile.tail >>Makefile ||
give_up_config "Can't create makefile properly"
echo ' '

mv config.h include/klic ||
give_up_config "Can't move config.h to an appropriate place"

clean_up_config

cat <<GAZONK
# All set!  Now you can compile the KLIC system by typing in "make all".
# If compilation is OK, I'd recommend testing it by running "make tests".
# You can then install the system by "make install".
#
# Good Luck!  Please report problems to "klic-bugs@icot.or.jp".

GAZONK
