#!/usr/bin/bash


##  ifor2exe
##  ========

#   With Intel Fortran, compile and link a TABLO-generated program
#   "BASENAME.for".
#   Usage: ifor2exe [-w WORDSIZE] BASENAME


##  bugs
##  ----

#   The script has been tested against only a few Intel Fortran versions and
#   configurations.

#   The determination of the environment for compiling and linking is fragile
#   and liable to be defeated by future changes in Intel Fortran and Microsoft
#   Visual Studio.

#   The identification of object files to be removed is fragile and liable to
#   be defeated by interrelated file names.


##  Define widely used objects.
##  --------------------------

self='ifor2exe'

function itcess { #Exit unsuccessfully.
    echo "ERROR: $self: $1" 1>&2
    exit 1
}

declare cesstect #processor architecture targeted by executable
declare gbasestem #stem of base name for Fortran program
declare gramrect #dir name for Fortran program
declare gprectwin=${GPDIR:-C:\\gp}
    #Windows-form pathname for GEMPACK directory
declare gprect=$(cygpath -u "$gprectwin") #pathname for GEMPACK directory
declare vironscript="$(mktemp)"
    #script to prepare environment for compiling and linking
declare pathwin
    #command path for environment for compiling and linking, in Windows form
declare -x LIB INCLUDE #for environment for compiling and linking


##  Check working environment.
##  -------------------------

#   Require Bash version 4 or higher, so that we can declare "figtargs" an
#   associative array.
declare -i bvermin=4 #required minimum bash version
declare -i bashver="${BASH_VERSINFO[0]}" #bash version number
[ "$bashver" -ge "$bvermin" ]\
    || itcess "Found Bash version \"$bashver\", but require at least \"$bvermin\"."
unset bashver bvermin

#   Check that "u2d" is available.
which u2d > /dev/null 2>/dev/null\
    || itcess "Can't find required command \"u2d\"."


##  Process arguments.
##  -----------------

#   Define widely used objects.
declare wordsize=32 #word size for executable

#   Process options.
while [ $# -gt 0 ] ; do
    case $1 in
    -w*)
        declare wsizearg="${1#-w}" #word size argument
        [ -z "$wsizearg" ] && {
            shift
            wsizearg="$1"
            [ -n "$wsizearg" ] || itcess "Can't find word size argument."
        }
        wordsize="$wsizearg"
        unset wsizearg
        ;;
    --)
        shift; break
        ;;
    -*)
        itcess "Found unknown option \"$1\"."
        ;;
    *)
        break
        ;;
    esac
    shift
done

#   Infer processor architecture from word size.
case "$wordsize" in
32)
    cesstect=ia32;;
64)
    cesstect=intel64;;
*)
    itcess "Don't recognize word size \"$wordsize\".";;
esac

#   Process filename argument.
declare gfnameread #program name, as read
declare gfstemread #stem of program name, as read
[ -n "$1" ] || itcess "Can't find argument."
if <<<"$1" grep -iq '\.for$' ; then
    gfnameread="$1"
    gfstemread="${gfnameread%.*}"
else
    gfstemread="$1"
    gfnameread="$1.for"
fi
[ -f "$(cygpath -u -- "$gfnameread")" ] \
    || itcess "Can't find source file \"$gfnameread\"."
gfilestem="$(cygpath -u -- "$gfstemread")"
gbasestem="$(basename -- "$gfilestem")"
gramrect="$(dirname -- "$gfilestem")"
unset gfilestem gfstemread gfnameread

#   Clean up.
unset wordsize


##  Change directory.
##  ----------------

cd -- "$gramrect"


##  Set options.
##  -----------

#   Copy configuration files.
declare -A figtargs=(
    [intel_1_ltg]=optin_1
    [intel_1_common]=intel_1_common.fig
    [intel_2]=optin_2
)   #targets to which configuration files are to be copied
declare figsource #configuration file to be copied
declare figtarg #target to which configuration file is to be copied
declare ftargstem #stem of target to which configuration file is to be copied
for ftargstem in "${!figtargs[@]}"; do
    figsource="$gprect/$ftargstem.fig"
    [ -f "$figsource" ]\
        || itcess "Can't find configuration file \"$figsource\"."
    figtarg="${figtargs["$ftargstem"]}"
    cp -- "$figsource" "$figtarg"\
        || itcess "Can't copy \"$figsource\" to \"$figtarg\"."
done; unset figsource figtarg ftargstem
unset figtargs

#   Set include path.
echo /I\"$gprectwin\\includes\" >>optin_1
echo /I\"$gprectwin\\modules\" >>optin_1

#   Declare libraries.
declare libstem #base name stem of library file
for libstem in gpa gpb tbgdum modlib; do
    lib="$gprect/$libstem.lib"
    [ -f "$lib" ] || itcess "Can't find GEMPACK library \"$lib\"."
    echo \"$gprectwin\\$libstem.lib\" >>optin_2
done; unset lib libstem

#   Set output file name.
echo /out:\"$gbasestem\".exe >>optin_2

#   Beautify.
u2d optin_1 optin_2 &>/dev/null


##  Define compilation and linking tasks.
##  ------------------------------------

gptask="$gprect/gptask.exe"
[ -f "$gptask" ] || itcess "Can't find gptask file \"$gptask\"."
"$gptask" intel "$gbasestem" &>"gptask.stderr" || itcess "Can't run gptask."
rm -f gptask.stderr
declare opt #options file
for opt in opt80 opt80_2; do
    [ -f "$opt" ] || itcess "Can't find options file \"$opt\"."
done; unset opt
unset gptask


##  Write script to prepare environment for compiling and linking.
##  -------------------------------------------------------------

declare vbatwin="$(cygpath -w "${libdir}/ivironcp.bat")"
    #Windows-form name for batch file to write script to prepare environment
    #for compiling and linking
cmd.exe /E:ON /V:ON /C "$vbatwin" $cesstect | d2u >"$vironscript"
unset vbatwin


##  Prepare environment for compiling and linking.
##  ---------------------------------------------

(
. "$vironscript"
pwinpart="${pathwin%;};"
    #part of Windows-form command path for compiling and linking
declare pathpart= #part of command path for compiling and linking
while [ -n "$pwinpart" ] ; do
    rectwin="${pwinpart%%;*}"
        #Windows-form directory on command path for compiling and linking
    pathpart="$pathpart:$(cygpath -u "$rectwin")"
    pwinpart="${pwinpart#*;}"
done
PATH="${pathpart#:}"
unset rectwin pathpart pwinpart


##  Compile and link.
##  ----------------

ifort @optin_1 @opt80 >ifort.stdout 2>ifort.stderr\
    || itcess "Can't compile \"$gbasestem\"."
rm -f ifort.stdout ifort.stderr
xilink @opt80_2 @optin_2 >xilink.stdout 2>xilink.stderr\
    || itcess "Can't link \"$gbasestem\"."
rm -f xilink.stdout xilink.stderr


##  Leave compilation environment.
##  -----------------------------

) || itcess "Encountered error in compilation subshell."


##  Clean up.
##  --------

declare modstem="${gbasestem##*[ .]}" #stem of names of module files
rm -f --\
    "$gbasestem"__[0-9][0-9].obj\
    "$gbasestem"__[0-9].obj\
    "$gbasestem"_[cmuv][0-9][0-9].obj\
    "$gbasestem"_[cmuv][0-9].obj\
    "$modstem"_[cmuv][0-9][0-9].mod\
    "$modstem"_[cmuv][0-9].mod\
    "$modstem"_.mod\
    opt80 opt80_2\
    "$gbasestem"__[0-9][0-9].for\
    "$gbasestem"__[0-9].for\
    optin_2 intel_1_common.fig optin_1
rm "$vironscript"
unset modstem INCLUDE LIB pathwin vironscript gprect gprectwin gramrect\
    gbasestem cesstect
unset -f itcess
unset self
exit 0


##  end of script
##  -------------
