#!/bin/sh
#!/usr/bin/posix/sh

#   toba -- build a Java program using Toba
#
#   Copyright 1996, 1997 Arizona Board of Regents; see COPYRIGHT file for 
#   details.
#
#
#   usage:  toba [options] file...
#
#   options:
#
#	-X		use directly executable version of Toba (default)
#	-J		use interpreted version of Toba
#
#	-K		run javac to produce .class files but go no further
#	-C		produce C files but don't compile or link them
#	-S		produce .s files but don't assemble or link them
#	-c		compile to .o files but do not link
#	-o filename	write executable to filename instead of a.out
#	-I path		set include path for C compiler
#			(note: Java API is always in path)
#	-g		pass -g (enable debugging) to cc
#	-O		pass -O (enable optimization) to cc
#	-A string	add string to args passed to cc
#
#	-i		delete intermediate files upon exit
#	-v 		("verbose") list commands executed
#	-w		suppress warnings from javac
#
#	-d flags	set debugging flags for Toba
#	-P packagedir	create a package in packagedir
#	-m mainclass	generate a main from mainclass
#	-r		recursively pull in all dependencies
#
#
#   file argument interpretation:
#
#	file.java	Java file to compile, translate, and link
#	file.class	class file to translate and link
#	file.c		C file to compile and link
#	file.o		object file to link
#	file.a		library to link
#	file.so		library to link
#	-lxxx		library to link (must follow a "normal" file)
#	-Lxxx		library directory to search (must follow "normal" file)
#	classname	Java class from $CLASSPATH to translate and link

# run toba with the Java interpreter
# CPATH should be computed before this is called
itoba()
{
    # $OSTYPE is a bash builtin variable and bash
    # is the /bin/sh that comes with cygwin
    ICPATH=$CPATH:$tobadir
    CLASSPATH=$ICPATH java -mx64m -Dtoba.class.path=$TOBAPATH toba.Trans "$@"
}

#  test if a file is newer than another
is_newer() {
    # use find to see if the file is older, ignoring all errors
    res=`find "$1" -newer "$2" 2>/dev/null || true`
    if [ "$res" = "$1" ] ; then
        return 0     # true
    else
        return 1     # false
    fi
}

#  execute command, possibly echoing to stdout
trace() {
    trap 'rm -f $TMP; exit 1' 1 2 15	# seems to be needed
    # sed protects dollar signs from expansion; tr protects sed from long lines
    CMD=`echo "$@" | tr ' ' '\012' | sed 's/\\$/\\\\$/g' | tr '\012' ' '`
    $ECHO + "$CMD"
    eval "$CMD" || exit 1
}

#  remove files; disabled by -i option
remove() {
    trap 'rm -f $TMP; exit 1' 1 2 15	# seems to be needed
    if [ $# -gt 0 ]; then
	$RMTRACE "$@"
    fi
}

RMTRACE=:

CUR_DIR=`pwd`
CUR_DIR=`basename $CUR_DIR`

REST_JAVA_DIRS=
PREV_JAVA_DIRS=
FOUND=0
for d in $JAVA_VDIRS ; do
    if [ $FOUND = 1 ] ; then
	REST_JAVA_DIRS="$REST_JAVA_DIRS $d"
    fi
    if [ "$d" = "$CUR_DIR" ] ; then
	FOUND=1
    fi
    if [ $FOUND = 0 ] ; then
	PREV_JAVA_DIRS="$PREV_JAVA_DIRS $d"
    fi
done

for d in $PREV_JAVA_DIRS ; do
    CFLAGS="$CFLAGS -I../$d -I$srcdir/../$d"
done

# explicit or implicit CLASSPATH, before we add to it
CPATH="${CLASSPATH:-.}"

CLPATH=
for d in $PREV_JAVA_DIRS ; do
    if [ "$d" != "packages" ] ; then
	CLPATH="$srcdir/../$d:$CLPATH"
    fi
done

if [ "$CUR_DIR" != "packages" ] ; then
    CLPATH="$srcdir:$CLPATH"
fi


TOBAPATH=
for d in $PREV_JAVA_DIRS ; do
    TOBAPATH="$srcdir/../$d:$TOBAPATH"
done

TOBAPATH="$srcdir:$TOBAPATH"


# paths for interpreted and executed javac and toba
IJAVAC=javac
ITOBA=itoba
XJAVAC=$TOP/fe/bin/xjavac
XTOBA=$TOP/fe/bin/xtoba

# default option values
TOBA=$ITOBA
JAVAC=$IJAVAC
NOTOBA=
NOCOMPILE=
NOLINK=
XFILE=a.out
PACKAGENAME=
INCLUDES=
JFLAGS=
TFLAGS="$TOBAOPTS"
LDFLAGS=


#  process command options

USAGE="usage: $0 [-cCgiJKOrSvwX] [-A arg] [-d flags] [-IP dir] [-m main] [-o file] file..."

while getopts cCgiJKOrSvwXA:d:I:m:o:P: c; do
    case $c in
	A)  CFLAGS="$CFLAGS $OPTARG";;
	d)  TFLAGS="$TFLAGS -d$OPTARG";;
	c)  NOLINK=exit;;
	C)  NOCOMPILE=exit;;
	g)  CFLAGS="$CFLAGS -g";;
	i)  RMTRACE="trace $RM";;
	I)  INCLUDES="$INCLUDES -I$OPTARG";;
	J)  TOBA=$ITOBA; JAVAC=$IJAVAC;;
	K)  NOTOBA=exit;;
        m)  TFLAGS="$TFLAGS -m $OPTARG";;
	o)  XFILE="$OPTARG";;
	O)  CFLAGS="$CFLAGS -O";  JFLAGS="$JFLAGS -O";;
        P)  PACKAGENAME="$OPTARG"
            TFLAGS="$TFLAGS -P $PACKAGENAME";;
        r)  TFLAGS="$TFLAGS -r";;
	S)  NOLINK=exit;  CFLAGS="$CFLAGS -S";;
	v)  ECHO=echo;;
	w)  JFLAGS="$JFLAGS -nowarn";;
	X)  TOBA=$XTOBA; JAVAC=$XJAVAC;;
	\?) echo $USAGE; exit 1;;
    esac
done


#  process file names

shift `expr $OPTIND - 1`

if [ $# = 0 ] ; then
    echo $USAGE
    exit 1
fi

JFILES=
KFILES=
CFILES=
LFILES=

for f in $*; do
    case $f in
	*.java)		JFILES="$JFILES $f";;
	*.class)	KFILES="$KFILES $f";;
	*.c)		CFILES="$CFILES $f";;
	*.cc)		CFILES="$CFILES $f";;
	*.h)		HFILES="$HFILES $f";;
	*.o)		OFILES="$OFILES $f";;
	*.a)		LFILES="$LFILES $f";;
	*.so)		LFILES="$LFILES $f";;
        -L*)		LFILES="$LFILES $f";;
	-l*)		LFILES="$LFILES $f";;
	*)		KFILES="$KFILES $f";;
    esac
done


#PKGS=$TOP/fe/java/packages
#STDTOBAPATH=$PKGS/sun:$PKGS/java
#if [ "x$TOBAPATH" != "x" ] ; then
#    trace TOBAPATH=$TOBAPATH:$STDTOBAPATH
#else
#    trace TOBAPATH=$STDTOBAPATH
#fi
#trace export TOBAPATH

# set JAVA_HOME in the same way javac would
PRG=`which java`
# Chandra: PRG=`whereis java` is not good because it searches only in system 
#          path and also because there could be multiple entries in it.
trace JAVA_HOME=`dirname $PRG`/..
trace export JAVA_HOME


# Process TOBAPATH to get library and include directories
#OLDIFS=$IFS
#IFS=:
#for component in $TOBAPATH ; do
#    BASE=`basename $component`
#    if [ -f $component/lib$BASE* ] ; then
#        INCLUDES="$INCLUDES -I$component/include"
#    fi
#done
#IFS=$OLDIFS


# exit on any errors beyond here
set -e

# stamp is preserved across calls to toba.
# create a very old stamp if this is the first time toba is being called
STAMP=stamp
if [ ! -f $STAMP ] ; then
    $TOUCH -t 7001010101 $STAMP
fi

# touch timestamp file; arrange deletion on exit
TMP=.tmp.toba.$$
trap 'rm -f $TMP' 0 1 2 15
# Chandra: touch $TMP doesnt work across nfs if the times on machines differ
$ECHO "" > $TMP
# is_newer needs at least one second delta to work properly. ugh
sleep 1


# Make package structure
if [ "x$PACKAGENAME" != "x" ] ; then
    test -d $PACKAGENAME         || trace mkdir $PACKAGENAME
    test -d $PACKAGENAME/include || trace mkdir $PACKAGENAME/include
    echo $LFILES > $PACKAGENAME/extraflags
fi

# Get only the source files that were modified after the last call to toba
OLDJFILES=$JFILES
JFILES=
for f in $OLDJFILES; do
    if is_newer $f $STAMP; then
        JFILES="$JFILES $f"
    fi
done

echo "$JFILES"

OLDKFILES=$KFILES
KFILES=
for f in $OLDKFILES; do
    if is_newer $f $STAMP; then
        KFILES="$KFILES $f"
    fi
done

OLDCFILES=$CFILES
CFILES=
for f in $OLDCFILES; do
    if is_newer $f $STAMP; then
        CFILES="$CFILES $f"
    fi
done

# compile Java files to bytecode
INT1=
if [ "x$JFILES" != "x" ]; then
    export JAVA_HOME  

    trace CLASSPATH="$CPATH:$CLPATH"
    trace export CLASSPATH

    # compute a list of directories java src is in, and compile the src
    JDIRS=`(echo .; for f in $JFILES ; do dirname $f; done) | sort | uniq`

    for f in $JFILES; do
	trace $JAVAC $JFLAGS $f
    done

    # find all new class files in the src directories
    INT1=
    for d in $JDIRS; do
        for f in $d/*.class; do
            if is_newer "$f" $TMP; then
                INT1="$INT1 $f"
            fi
        done
    done
    KFILES="$KFILES $INT1"
fi

# exit if -S given
$NOTOBA


# translate bytecode to C code
INT2=
if [ "x$KFILES" != "x" ]; then
    trace CLASSPATH="$CPATH:$tobadir"
    trace export CLASSPATH

    for f in $KFILES; do
	trace $TOBA $TFLAGS $f
    done

    remove $INT1

    INT2=
    for f in *.c; do
        if is_newer "$f" $TMP ; then
            INT2="$INT2 $f"
        fi
    done     
    if [ "x$INT2" != "x" ] ; then
        CFILES="$CFILES $INT2"
    fi

    INT2h=
    for f in *.h; do
        if is_newer "$f" $TMP ; then
            INT2h="$INT2h $f"
        fi
    done     
    if [ "x$INT2h" != "x" ] ; then
        HFILES="$HFILES $INT2h"
    fi
fi

# preserve headers when rolling packages
if [ "x$PACKAGENAME" != "x" ] ; then
    if [ "x$HFILES" != "x" ] ; then
        trace cp $HFILES $PACKAGENAME/include
    fi
fi 

# exit if -C given
$NOCOMPILE

if [ ! -d exports ] ; then 
    mkdir exports
fi	

PKG=java

TMP2=tmp.toba.ihrou

$RM exports/$PKG.h
$TOUCH $TMP2.h
$TOUCH $srcdir/$TMP2.h
cat *.h $srcdir/*.h > exports/$PKG.h
$RM $TMP2.h
$RM $srcdir/$TMP2.h

$RM exports/$PKG.externs.h
$TOUCH $TMP2.externs.h
$TOUCH $srcdir/$TMP2.externs.h
cat *.externs.h $srcdir/*.externs.h > exports/$PKG.externs.h 
$RM $TMP2.externs.h
$RM $srcdir/$TMP2.externs.h

$RM exports/$PKG.data.old
$TOUCH exports/$PKG.data
mv -f exports/$PKG.data exports/$PKG.data.old
$TOUCH $TMP2.data
$TOUCH $srcdir/$TMP2.data
cat *.data $srcdir/*.data > exports/$PKG.data 
$RM $TMP2.data
$RM $srcdir/$TMP2.data

cmp -s exports/$PKG.data exports/$PKG.data.old || \
    for d in $REST_JAVA_DIRS ; do
	echo "Removing $d/$STAMP"
	(cd ../$d; 
	$RM $STAMP; 
	if [ ! -d exports ] ; then 
	    mkdir exports
	fi	
	$TOUCH exports/java.data)
    done

#(cd $TOP/fe/boot; make fe_wk_xref.h)

# compile .c files
INT3=
if [ "x$CFILES" != "x" ]; then
    trace $CC $CFLAGS -c $CFILES 2>&1 | grep -v "In function" | grep -v memcpy | grep -v "defined but not used" | grep -v "unused variable" | grep -v "control reaches end of non-void function"
    remove $INT2
    remove $INT2h

    # following "tr" segments prevent sed from getting lines too long
    #INT3=`echo "$CFILES " | tr ' ' '\012' | sed 's/\.c$/.o/g'`
    #INT3o=
    #for f in $INT3; do
	#INT3o="$INT3o `basename $f`"
    #done
    #INT3="$INT3o"
    #OFILES="$OFILES $INT3#"

    for f in *.o; do
	OFILES="$OFILES $f"
    done
fi

# exit if -c given
$NOLINK


LIB=exports/$PKG.a

# link .o files together
if [ "x$OFILES" != "x" ]; then
    trace $RM $LIB
    trace $AR cq $LIB $OFILES
    trace $RANLIB $LIB
    remove $INT3
fi

$RM $STAMP
$ECHO "" > $STAMP
