#!/usr/bin/env bash
# flx - felix script harness
INSTALL_ROOT=/usr//lib/felix/felix-1.1.3_rc4
FLX_INSTALL_DIR=${FLX_INSTALL_DIR:-$INSTALL_ROOT}
CYGWIN=0
WIN32=0
MACOSX=0
HAVE_GNU=1
HAVE_MSVC=0
CCOBJ_DLLIB="g++ -fPIC -c -Wall -Wno-invalid-offsetof -Wfatal-errors "
CCLINK_DLLIB="g++ -shared "
CCOBJ_STATIC_LIB="g++ -c -Wall -Wno-invalid-offsetof -Wfatal-errors "
CCLINK_STATIC="g++ "
VERSION="1.1.3_rc4"
EXT_LIB=".a"
EXT_STATIC_OBJ="_static.o"
EXT_SHARED_OBJ="_dynamic.o"
EXT_EXE=""
EXT_SHLIB=".so"
SPEC_OBJ_FILENAME="-o "
SPEC_EXE_FILENAME="-o "
OPTIMISE="-O3 -fomit-frame-pointer --inline "
DEBUG_FLAGS="-g "
PTHREAD_SWITCH="-lpthread "
# 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
LINKER_SWITCHES=""
MACROS=""
grab=1
cpps=""
cppos=""
INCLUDE_DIRS=""

while (( "$grab" == "1" ));
do
  case x$1 in
  x--test=*)
    TESTMODE=1
    FLX_INSTALL_DIR=${1:7}
    shift
  ;;

  x--test)
    TESTMODE=1
    FLX_INSTALL_DIR=.
    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-[lL]*)
   LINKER_SWITCHES="$LINKER_SWITCHES $1"
   shift
  ;;

  x-D*)
   MACROS="$MACROS $1"
   shift
  ;;

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

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

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

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

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

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

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

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

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

# the main filename -- subsequent args are args to flx_run
  x*)
    grab=0
  ;;

  esac
done

DLINK_STRING="-L${FLX_INSTALL_DIR}/rtl "
SLINK_STRING="-L${FLX_INSTALL_DIR}/rtl "
PKGCONFIG=$FLX_INSTALL_DIR/bin/flx_pkgconfig

if [ "$ECHO" = "1" ]
then
  echo "#FLX_INSTALL_DIR=$FLX_INSTALL_DIR"
  echo "#PKGCONFIG=$PKGCONFIG"
fi


# find external header files
PKGCONFIG_CFLAGS="$PKGCONFIG --path+=$FLX_INSTALL_DIR/config --field=cflags "

# find external dynload libraries
PKGCONFIG_DLIBS="$PKGCONFIG -r --path+=$FLX_INSTALL_DIR/config --field=provides_dlib --field=requires_dlibs "

# find external static libraries
PKGCONFIG_SLIBS="$PKGCONFIG -r --keeprightmost --path+=$FLX_INSTALL_DIR/config --field=provides_slib --field=requires_slibs "

#find driver package required
PKGCONFIG_DRIVER="$PKGCONFIG --path+=$FLX_INSTALL_DIR/config --field=flx_requires_driver "

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

if [ $STATIC = 0 ]
then
  EXT_OBJ=$EXT_SHARED_OBJ
else
  EXT_OBJ=$EXT_STATIC_OBJ
fi

if [ "x$1" = "x" ]
then
  echo "usage: flx [options] 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

function calpackages () {
  # find all include directories
  if [ "$ECHO" = "1" ]
  then
    echo "$PKGCONFIG_CFLAGS @$base.resh"
  fi

  INCLUDE_DIRS="$INCLUDE_DIRS $($(echo $PKGCONFIG_CFLAGS @$base.resh))"

  if [ "$ECHO" = "1" ]
  then
    echo "$PKGCONFIG_DRIVER @$base.resh"
  fi

  # find the driver package
  DRIVER_PKG=$($(echo $PKGCONFIG_DRIVER @$base.resh))
  if [ x$DRIVER_PKG = x ]
  then
    # default to flx_run if none specified
    DRIVER_PKG=flx_run
  fi

  # find the driver entity
  if [ $STATIC = 0 ]
  then
    # dynamic linkage: the driver executable
    DRIVER=$FLX_INSTALL_DIR/bin/$DRIVER_PKG$EXT_EXE
  else
    # static linkage: the driver object file
    DRIVER=$FLX_INSTALL_DIR/rtl/$DRIVER_PKG$EXT_STATIC_OBJ
  fi

  if [ $STATIC = 0 ]
  then
    if [ "$ECHO" = "1" ]
    then
     echo "$PKGCONFIG_DLIBS @$base.resh"
    fi

    # dynamic linkage: all the libraries required by the application
    LINK_STRING="$DLINK_STRING$LINKER_SWITCHES $($(echo $PKGCONFIG_DLIBS @$base.resh))"
  else
    if [ "$ECHO" = "1" ]
    then
     echo "$PKGCONFIG_SLIBS $DRIVER_PKG @$base.resh"
    fi

    # static linkage: all the libraries required by the application and driver
    LINK_STRING="$SLINK_STRING$LINKER_SWITCHES $($(echo $PKGCONFIG_SLIBS $DRIVER_PKG @$base.resh))"
  fi

  if [ $ECHO = 1 ]
  then
    echo "#RESOURCE FILE=$base.resh"
    echo "#INCLUDE_DIRS=$INCLUDE_DIRS"
    echo "#DRIVER=$DRIVER"
    echo "#LINK_STRING=$LINK_STRING"
  fi

}

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

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

INCLUDE_DIR="-I$FLX_INSTALL_DIR/rtl"
FLXLIB="-I$FLX_INSTALL_DIR/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=$FLX_INSTALL_DIR/bin:\$PATH\" $FLX_INSTALL_DIR/bin/flxg"
  FLXRUN="env \"PATH=$FLX_INSTALL_DIR/bin:\$PATH\" "
else
  FLXG="env PATH=$FLX_INSTALL_DIR/bin:\$PATH $FLX_INSTALL_DIR/bin/flxg"
  # the mac uses DYLD_LIBRARY_PATH instead of LD_LIBRARY_PATH
  if [ "$MACOSX" = "1" ]
  then
    FLXRUN="env DYLD_LIBRARY_PATH=$FLX_INSTALL_DIR/rtl:\$DYLD_LIBRARY_PATH "
  else
    FLXRUN="env LD_LIBRARY_PATH=$FLX_INSTALL_DIR/rtl:\$LD_LIBRARY_PATH "
  fi
fi
ELKHOUND="--elkhound=$FLX_INSTALL_DIR/bin/flx_elkhound"

DEBUGSWITCH=""
if [ "$DEBUG" = "1" ]; then DEBUGSWITCH=" --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
      calpackages
      cmd="$FLXRUN$DRIVER$DEBUGSWITCH $base$EXT_SHLIB $args"
      if [ $ECHO = 1 ]; then echo $cmd; fi
      eval $cmd
      exit $?
    fi
  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
      exit $?
    fi
  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 $ELKHOUND $FLXLIB $INCLUDE_DIRS $base"
    if [ $ECHO = 1 ]; then echo "$FCMD"; fi
    eval $FCMD
  fi
  if [ $? = 0 ]
  then
    calpackages
    CCMD="$CCOBJ_DLLIB $CCFLAGS -DTARGET_BUILD $INCLUDE_DIR $INCLUDE_DIRS $MACROS $cpps $base.cpp $SPEC_OBJ_FILENAME$base$EXT_OBJ"
    LCMD="$CCLINK_DLLIB $CCFLAGS $cppos $base$EXT_OBJ $SPEC_EXE_FILENAME$base$EXT_SHLIB $LINK_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$DRIVER$DEBUGSWITCH $base$EXT_SHLIB $args"
          else
            cmd="$FLXRUN$DRIVER$DEBUGSWITCH $base$EXT_SHLIB $args"
          fi
          if [ $ECHO = 1 ]; then echo $cmd; fi
          eval $cmd
        fi
      fi
    fi
  fi
else
  if [ $FELIX = 1 ]
  then
    FCMD="$FLXG $VERBOSE $FLXFLAGS $ELKHOUND $FLXLIB $INCLUDE_DIRS $base"
    if [ $ECHO = 1 ]; then echo "$FCMD"; fi
    eval $FCMD
  fi
  if [ $? = 0 ]
  then
    calpackages
    CCMD="$CCOBJ_STATIC_LIB $CCFLAGS -DTARGET_BUILD -DFLX_STATIC_LINK $INCLUDE_DIR $INCLUDE_DIRS $MACROS $cpps $base.cpp $SPEC_OBJ_FILENAME$base$EXT_OBJ"
    LCMD="$CCLINK_STATIC $SPEC_EXE_FILENAME$base$EXT_EXE $base$EXT_OBJ ${DRIVER} $cppos $LINK_STRING"
    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
      fi
    fi
  fi
fi
exit $?

