#!/bin/sh

# nacl/do
# D. J. Bernstein
# Public domain.

version=`cat version`
project=nacl
shorthostname="localhost"

top="`pwd`/build/$shorthostname"
bin="$top/bin"
lib="$top/lib"
include="$top/include"
work="$top/work"

PATH="/usr/local/bin:$PATH"
PATH="/usr/sfw/bin:$PATH"
PATH="$bin:$PATH"
export PATH

LD_LIBRARY_PATH="/usr/local/lib/sparcv9:/usr/local/lib:$LD_LIBRARY_PATH"
LD_LIBRARY_PATH="/usr/sfw/lib/sparcv9:/usr/sfw/lib:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH

# and wacky MacOS X
DYLD_LIBRARY_PATH="/usr/local/lib/sparcv9:/usr/local/lib:$DYLD_LIBRARY_PATH"
DYLD_LIBRARY_PATH="/usr/sfw/lib/sparcv9:/usr/sfw/lib:$DYLD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH

# and work around bug in GNU sort
LANG=C
export LANG

rm -rf "$top"
mkdir -p "$top"
mkdir -p "$bin"
mkdir -p "$lib"
mkdir -p "$include"

exec 5>"$top/data"
exec 2>"$top/errors"
exec </dev/null

echo "=== `date` === starting"

echo "=== `date` === hostname"
hostname || :
echo "=== `date` === uname -a"
uname -a || :
echo "=== `date` === uname -M"
uname -M || :
echo "=== `date` === uname -F"
uname -F || :
echo "=== `date` === /usr/sbin/lscfg | grep proc"
/usr/sbin/lscfg | grep proc || :
echo "=== `date` === /usr/sbin/lsattr -El proc0"
/usr/sbin/lsattr -El proc0 || :
echo "=== `date` === cat /proc/cpuinfo"
cat /proc/cpuinfo || :
echo "=== `date` === cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq || :
echo "=== `date` === cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq || :
echo "=== `date` === cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq || :
echo "=== `date` === cat /sys/devices/system/cpu/cpu0/clock_tick"
cat /sys/devices/system/cpu/cpu0/clock_tick || :
echo "=== `date` === sysctl hw.model"
sysctl hw.model || :
echo "=== `date` === sysctl machdep.tsc_freq"
sysctl machdep.tsc_freq || :
echo "=== `date` === /usr/sbin/psrinfo -v"
/usr/sbin/psrinfo -v || :

echo "=== `date` === building okcompilers"
rm -rf "$work"
mkdir -p "$work"
cp -pr okcompilers/* "$work"
( cd "$work" && sh do )
cp -p "$work"/bin/* "$bin"

echo "=== `date` === copying windows headers"
mkdir -p "${include}/windows"
cp -pr windows/include/* "${include}/windows/"

echo "=== `date` === building cpuid"
rm -rf "$work"
mkdir -p "$work"
cp -pr cpuid/* "$work"
( cd "$work" && sh do )
cp -pr "$work"/include/* "$include"

echo "=== `date` === building inttypes"
rm -rf "$work"
mkdir -p "$work"
cp -pr inttypes/* "$work"
( cd "$work" && sh do )
cp -pr "$work"/include/* "$include"

echo "=== `date` === building cpucycles"
rm -rf "$work"
mkdir -p "$work"
cp -pr cpucycles/* "$work"
( cd "$work" && sh do )
cp -pr "$work"/lib/* "$lib"
cp -pr "$work"/include/* "$include"

echo "=== `date` === building randombytes"
rm -rf "$work"
mkdir -p "$work"
cp -pr randombytes/* "$work"
( cd "$work" && sh do )
cp -pr "$work"/lib/* "$lib"
cp -pr "$work"/include/* "$include"

okabi \
| while read abi
do
  rm -rf "$work"
  mkdir -p "$work"
  echo 'void crypto_'"$project"'_base(void) { ; }' > "$work/${project}_base.c"
  okc-$abi \
  | while read compiler
  do
    ( cd "$work" && $compiler -c ${project}_base.c ) && break
  done
  okar-$abi cr "$lib/$abi/lib${project}.a" "$work/${project}_base.o"
  ( okranlib-$abi "$lib/$abi/lib${project}.a" || exit 0 )
done

ulimit -c 0

# loop over operations
cat OPERATIONS \
| while read o
do
  [ -d "$o" ] || continue

  selected=''
  [ -f "$o/selected" ] && selected=`cat "$o/selected"`

  # for each operation, loop over primitives
  ls "$o" \
  | sort \
  | while read p
  do
    [ -d "$o/$p" ] || continue
    expectedchecksum=''
    [ -f "$o/$p/checksum" ] && expectedchecksum=`cat "$o/$p/checksum"`
    op="${o}_${p}"

    startdate=`date +%Y%m%d`

    # for each operation primitive, loop over abis
    okabi \
    | while read abi
    do
      echo "=== `date` === $abi $o/$p"
      libs=`"oklibs-$abi"`
      libs="$lib/$abi/cpucycles.o $libs"
      [ -f "$lib/$abi/lib${project}.a" ] && libs="$lib/$abi/lib${project}.a $libs"

      rm -rf "$work"
      mkdir -p "$work"
      mkdir -p "$work/best"

      # for each operation primitive abi, loop over implementations
      find "$o/$p" -follow -name "api.h" \
      | sort \
      | while read doth
      do
        implementationdir=`dirname $doth`
	opi=`echo "$implementationdir" | tr ./- ___`

	echo "=== `date` === $abi $implementationdir"

	rm -rf "$work/compile"
	mkdir -p "$work/compile"

	cfiles=`ls "$implementationdir" | grep '\.c$' || :`
	sfiles=`ls "$implementationdir" | grep '\.[sS]$' || :`

	cp -p "$o"/*.c "$work/compile/"

	cp -pr "$implementationdir"/* "$work/compile"

	cp -p "try-anything.c" "$work/compile/try-anything.c"

	cp -p MACROS "$work/compile/MACROS"
	cp -p PROTOTYPES.c "$work/compile/PROTOTYPES.c"

	(
	  cd "$work/compile"
	  (
	    echo "#ifndef ${o}_H"
	    echo "#define ${o}_H"
	    echo ""
	    echo "#include \"${op}.h\""
	    echo ""
	    egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' < MACROS \
	    | sed "s/$o/$op/" | while read mop
	    do
	      echo "#define ${mop} ${mop}" | sed "s/$op/$o/"
	    done
	    echo "#define ${o}_PRIMITIVE \"${p}\""
	    echo "#define ${o}_IMPLEMENTATION ${op}_IMPLEMENTATION"
	    echo "#define ${o}_VERSION ${op}_VERSION"
	    echo ""
	    echo "#endif"
	  ) > "$o.h"
	  (
	    echo "#ifndef ${op}_H"
	    echo "#define ${op}_H"
	    echo ""
	    sed 's/[ 	]CRYPTO_/ '"${opi}"'_/g' < api.h
	    echo '#ifdef __cplusplus'
	    echo '#include <string>'
	    echo 'extern "C" {'
	    echo '#endif'
	    egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' < PROTOTYPES.c \
	    | sed "s/$o/$opi/"
	    echo '#ifdef __cplusplus'
	    echo '}'
	    echo '#endif'
	    echo ""
	    egrep "${o}"'$|'"${o}"'\(|'"${o}"'_' < MACROS \
	    | sed "s/$o/$opi/" | while read mopi
	    do
	      echo "#define ${mopi} ${mopi}" | sed "s/$opi/$op/"
	    done
	    echo "#define ${op}_IMPLEMENTATION \"${implementationdir}\""
	    echo "#ifndef ${opi}_VERSION"
	    echo "#define ${opi}_VERSION \"-\""
	    echo "#endif"
	    echo "#define ${op}_VERSION ${opi}_VERSION"
	    echo ""
	    echo "#endif"
	  ) > "$op.h"

	  okc-$abi \
	  | while read compiler
	  do
	    echo "=== `date` === $abi $implementationdir $compiler"
	    compilerword=`echo "$compiler" | tr ' ' '_'`
	    ok=1
	    for f in $cfiles $sfiles
	    do
	      if [ "$ok" = 1 ]
	      then
		$compiler \
		  -I. -I"$include" -I"$include/$abi" \
		  -c "$f" >../errors 2>&1 || ok=0
		( if [ `wc -l < ../errors` -lt 25 ]
		  then
		    cat ../errors
		  else
		    head ../errors
		    echo ...
		    tail ../errors
		  fi
		) \
		| while read err
		do
		  echo "$version $shorthostname $abi $startdate $o $p fromcompiler $implementationdir $compilerword $f $err" >&5
		done
	      fi
	    done

	    [ "$ok" = 1 ] || continue
	    okar-$abi cr "$op.a" *.o || continue
	    okranlib-$abi "$op.a"

	    $compiler \
	      -I. -I"$include" -I"$include/$abi" \
	      -o try try.c try-anything.c \
	      "$op.a" $libs >../errors 2>&1 || ok=0
	    cat ../errors \
	    | while read err
	    do
	      echo "$version $shorthostname $abi $startdate $o $p fromcompiler $implementationdir $compilerword try.c $err" >&5
	    done
	    [ "$ok" = 1 ] || continue

	    rm -f ../best/*.o || continue
	    for f in *.o
	    do
	      cp -p "$f" "../best/${opi}-$f"
	    done
	    cp -p "$op.h" "../$op.h"
	    cp -p "$o.h" "../$o.h"
	  done
	)
      done

      [ -f "$o/$p/used" ] \
      && okar-$abi cr "$lib/$abi/lib${project}.a" "$work/best"/*.o \
      && ( okranlib-$abi "$lib/$abi/lib${project}.a" || exit 0 ) \
      && cp -p "$work/$op.h" "$include/$abi/$op.h" \
      && [ -f "$o/$p/selected" ] \
      && cp -p "$work/$o.h" "$include/$abi/$o.h" \
      || :
    done
  done
done

echo "=== `date` === finishing"

touch .done
