#!/usr/bin/env bash
# flx - felix script harness

CYGWIN=0
WIN32=0
HAVE_GXX=1
HAVE_MSVC=0
CCOBJ_DLLIB="g++ -fPIC -c -Wall -Wno-invalid-offsetof "
CCLINK_DLLIB="g++ -shared "
CCOBJ_STATIC_LIB="g++ -c -Wall -Wno-invalid-offsetof "
CCLINK_STATIC="g++ "
VERSION="1.1.1_rc1"
EXT_LIB=".a"
EXT_OBJ=".o"
EXT_EXE=""
EXT_SHLIB=".so"
SPEC_OBJ_FILENAME="-o "
SPEC_EXE_FILENAME="-o "
OPTIMISE="-O3 -fomit-frame-pointer --inline -DNDEBUG "
DEBUG_FLAGS="-g "
DYNLINK_STRING='-Lrtl -lflx_dynamic'
# check for test mode: this argument must come first

TESTMODE=0
RECOMPILE=0
DEBUG=0
INLINE=10
ECHO=0
TIME=0
STATIC=0
RUNIT=1
CCFLAGS=""
FELIX=1
grab=1

INCLUDE_DIRS=""

while (( "$grab" == "1" ));
do
  case x$1 in
  x--test)
    TESTMODE=1
    shift
  ;;

  x--force)
    RECOMPILE=1
    shift
  ;;

  x--debug)
    DEBUG=1
    ECHO=1
    shift
  ;;

  x--time)
    TIME=1
    shift
  ;;

  x--echo)
    ECHO=1
    shift
  ;;

  x--static)
    STATIC=1
    shift
  ;;

  x--inline=*)
    INLINE=${1:9}
    shift
  ;;

  x--inline)
    INLINE=50
    shift
  ;;

  x--noinline)
    INLINE=0
    shift
  ;;

  x--opt=1)
    INLINE=10
    CCFLAGS="-O1 $CCFLAGS"
    shift
  ;;

  x--opt=2)
    INLINE=20
    CCFLAGS="$CCFLAGS$OPTIMISE"
    shift
  ;;

  x--opt=3)
    INLINE=50
    CCFLAGS="$CCFLAGS$OPTIMISE"
    shift
  ;;

  x--optimise)
    INLINE=10
    CCFLAGS="$CCFLAGS$OPTIMISE"
    shift
  ;;

  x--optimize)
    INLINE=10
    CCFLAGS="$CCFLAGS$OPTIMISE"
    shift
  ;;

  x--version)
    echo $VERSION
    exit 0
  ;;

  x--help)
    man flx
    exit 0
  ;;

  x-c)
    RUNIT=0
    shift
  ;;

  x-I*)
    INCLUDE_DIRS="$INCLUDE_DIRS $1"
    shift
  ;;

  x--nofelix)
    FELIX=0
    shift
  ;;

  x*)
    grab=0
  ;;

  esac
done

if [ "$TESTMODE" = "1" -a "$ECHO" = "1" ]
then
  echo "TESTMODE: running felix from current directory"
fi

# make a list of any *.cpp files (or other g++ options ..)

cpps=""
cppos=""
grab=1
pkgs=""
while (( "$grab" == "1" ));
do
  case "$1" in
    *.cpp)
      cpps="$cpps $1"
      cppos="$cppos `dirname $1`/`basename $1 .cpp`$EXT_OBJ"
      shift
    ;;

    *.cxx)
      cpps="$cpps $1"
      cppos="$cppos `dirname $1`/`basename $1 .cxx`$EXT_OBJ"
      shift
    ;;

    *.c)
      cpps="$cpps $1"
      cppos="$cppos `dirname $1`/`basename $1 .c`$EXT_OBJ"
      shift
    ;;

    *.o)
      cppos="$cppos `dirname $1`/`basename $1 .o`$EXT_OBJ"
      shift
    ;;

    *.obj)
      cppos="$cppos `dirname $1`/`basename $1 .obj`$EXT_OBJ"
      shift
    ;;

    *.a)
      cppos="$cppos $1"
      shift
    ;;

    *.lib)
      cppos="$cppos $1"
      shift
    ;;

    --pkg=*)
      pkgs=" `echo \"$1\" | sed 's/--pkg=\(.*\)/\\1/'`"
      shift
    ;;

# unknown flag .. pass to both compile and link
    -*)
      cpps="$cpps $1"
      cppos="$cppos $1"
      shift
    ;;

    *)
      grab=0
    ;;
  esac
done

if [ "x$pkgs" = "x" ]
then
  PKGS=""
else
  PKGS=`pkg-config --cflags --libs $pkgs`
fi

if [ "x$1" = "x" ]
then
  echo "usage: flx filename"
  exit 1
fi

# Strip trailing .flx or .so
# users should type 'flx file' without extension,
# but #! interpreter always passes extension ..

case "$1" in
  *.flx)
    arg="`echo $1 | sed 's/\.flx$//'`"
    is_flx=1
  ;;

  *.so)
    arg="`echo $1 | sed 's/\.so$//'`"
    is_so=1
  ;;

  *)
    arg="$1"
esac

# Find absolute pathname

base=$arg

if [ "x$base" = "x" ]
then
  echo "No such felix program: $arg" >&2
  exit 1
fi

shift

# grab arguments
grab=1
args=""
while (( "$grab" == "1" ));
do
  case "x$1" in
    x)
      grab=0
    ;;

    x*)
      args="$args $1"
      shift
    ;;
 esac
done

if [ "$TESTMODE" = "1" ]
then
  INCLUDE_DIR="./rtl"
  FLXLIB="./lib"
  if [ "$CYGWIN" = "1" -o "$WIN32" = "1" ]
  then
    # bash is a heap of crap! The escaped quotes here are
    # required in case the PATH has a filename with spaces
    # However this actually fails on Linux!
    FLXG="env \"PATH=./bin:\$PATH\" ./bin/flxg"
    FLXRUN="env \"PATH=./bin:\$PATH\" ./bin/flx_run"
  else
    FLXG="env PATH=./bin:\$PATH ./bin/flxg"
    FLXRUN="env LD_LIBRARY_PATH=./rtl:\$LD_LIBRARY_PATH ./bin/flx_run"
  fi
  FLXRTL="./rtl"
  FLXBIN="./bin"
  FLXAR="./rtl"
  if [ "$CYGWIN" = "1" -o "$WIN32" = "1" ]
  then
    FLXSHLIB="./bin"
  else
    FLXSHLIB="./rtl"
  fi
else
  # Locate the felix installation
  prefix=""
  for dir in `echo "$PATH" | sed 's/:/ /g'`
  do
    dir=$dir
    if [ -x "$dir/flxg" ]
    then
      prefix="$dir/flxg"
      break
    fi
  done
  prefix="`echo $prefix | sed 's/\/bin\/flxg$//'`"
  INCLUDE_DIR="$prefix/lib/felix/rtl"
  FLXG="$prefix/bin/flxg"
  FLXRUN="$prefix/bin/flx_run"
  FLXLIB="$prefix/lib/felix/lib"
  FLXRTL="$prefix/lib/felix/rtl"
  FLXBIN="$prefix/bin"
  FLXAR="$prefix/lib"
  if [ "$CYGWIN" = "1" -o "$WIN32" = "1" ]
  then
    FLXSHLIB="$prefix/bin"
  else
    FLXSHLIB="$prefix/lib"
  fi
fi
if [ "$DEBUG" = "1" ]; then FLXRUN="$FLXRUN --debug"; fi
STATIC_ENV=""
if [ "$DEBUG" = "1" ]; then STATIC_ENV="env FLX_DEBUG=1 "; fi

# No need to compile, just run it
if [ $STATIC = 0 ]
then
  if [ $RECOMPILE = 0 -a -r "$base$EXT_SHLIB" -a "(" ! -r "$base.flx" -o "$base$EXT_SHLIB" -nt "$base.flx" ")" ]
  then
    if [ $RUNIT = 1 ]
    then
      cmd="$FLXRUN $base$EXT_SHLIB $args"
      if [ $ECHO = 1 ]; then echo $cmd; fi
      eval $cmd
    fi
    exit $?
  fi
else
  if [ $RECOMPILE = 0 -a -r "$base$EXT_EXE" -a "(" ! -r "$base.flx" -o "$base$EXT_EXE" -nt "$base.flx" ")" ]
  then
    if [ $RUNIT = 1 ]
    then
      cmd="$STATIC_ENV $base $args"
      if [ $ECHO = 1 ]; then echo $cmd; fi
      eval $cmd
    fi
    exit $?
  fi
fi

# Need Felix and c++ compile, then run it

if [ $DEBUG = 1 ]
then
  VERBOSE="-v"
  CCFLAGS="$CCFLAGS$DEBUG_FLAGS"
else
  VERBOSE="-q"
fi

FLXFLAGS="--inline=$INLINE"

if [ $STATIC = 0 ]
then
  if [ $FELIX = 1 ]
  then
    FCMD="$FLXG $VERBOSE $FLXFLAGS -I$FLXLIB $INCLUDE_DIRS $base"
    if [ $ECHO = 1 ]; then echo "$FCMD"; fi
    eval $FCMD
  fi
  if [ $? = 0 ]
  then
    CCMD="$CCOBJ_DLLIB $CCFLAGS -I$INCLUDE_DIR $INCLUDE_DIRS $PKGS $cpps $base.cpp $SPEC_OBJ_FILENAME$base$EXT_OBJ"
    LCMD="$CCLINK_DLLIB $CCFLAGS $PKGS $cppos $base$EXT_OBJ $SPEC_EXE_FILENAME$base$EXT_SHLIB $DYNLINK_STRING"
    if [ $ECHO = 1 ]; then echo "$CCMD"; fi
    if `echo $CCMD`
    then
      if [ $ECHO = 1 ]; then echo "$LCMD"; fi
      if `echo $LCMD`
      then
        if [ $RUNIT = 1 ]
        then
          if [ $TIME = 1 ]
          then
            cmd="time $FLXRUN $base$EXT_SHLIB $args"
          else
            cmd="$FLXRUN $base$EXT_SHLIB $args"
          fi
          if [ $ECHO = 1 ]; then echo $cmd; fi
          eval $cmd
        fi
        exit $?
      else
        exit $?
      fi
    else
      exit $?
    fi
  fi
else
  if [ $FELIX = 1 ]
  then
    FCMD="$FLXG $VERBOSE $FLXFLAGS -I$FLXLIB $INCLUDE_DIRS $base"
    if [ $ECHO = 1 ]; then echo "$FCMD"; fi
    eval $FCMD
  fi
  if [ $? = 0 ]
  then
    CCMD="$CCOBJ_STATIC_LIB $CCFLAGS -DFLX_STATIC_LINK -I$INCLUDE_DIR $INCLUDE_DIRS $PKGS $cpps $base.cpp $SPEC_OBJ_FILENAME$base$EXT_OBJ"
    LCMD="$CCLINK_STATIC $FLXRTL/flx_run_static$EXT_OBJ $PKGS $cppos $base$EXT_OBJ $FLXAR/libflx_static$EXT_LIB $SPEC_EXE_FILENAME$base$EXT_EXE"
    if [ $ECHO = 1 ]; then echo "$CCMD"; fi
    if `echo $CCMD`
    then
      if [ $ECHO = 1 ]; then echo "$LCMD"; fi
      if `echo $LCMD`
      then
        # rm -f "$base.cpp"
        if [ $RUNIT = 1 ]
        then
          if [ $TIME = 1 ]
          then
            cmd="time $STATIC_ENV $base $args"
          else
            cmd="$STATIC_ENV $base $args"
          fi
          if [ $ECHO = 1 ]; then echo $cmd; fi
          eval $cmd
        fi
        exit $?
      else
        exit $?
      fi
    else
      exit $?
    fi
  fi
fi

