#!/bin/bash

BINDIR="`dirname $0`"

# TO DO: add -l and -L options to command line to add libraries to linking stage.
# for now just add explicit .c files.
# Also need to allow .asm and .o files on command line as well as .c

grab() {
  if   [ X"\`which wget\`" != X"" ] ; then
    echo -n wget -q $1 -O `basename $1`
  elif [ X"\`which curl\`" != X"" ] ; then
    echo -n curl -s -S -L -O `basename $1`
  elif [ X"\`which lynx\`" != X"" ] ; then
    echo -n lynx -dump $1 \> `basename $1`
  else
    echo -n manually fetch $1 with wget/curl/lynx etc...
    #echo "You really need to install a program to fetch $1 from the web."
    #echo "Try one of:"
    #echo "  sudo apt-get install wget"
    #echo "  sudo apt-get install curl"
    #echo "  sudo apt-get install lynx"
  fi
}

check() {
  if [[ "`arch`" == "arm"* ]] ; then
      echo "Unfortunately  I'm not aware of a compiled gcc6809 for arm. You'll either have"
      echo "to port gcc yourself, or install wine on your arm processor, which if it is a"
      echo "Raspberry Pi will need something like \"pi386\" to make it work."
      exit 1
  fi
  if [ ! -f $BINDIR/cc1 ] && [ ! -f $BINDIR/gcc6809.exe ]; then
      if [ X`arch` = Xi686 ] || [ X`arch` = Xx86_64 ]; then
        echo "Try:"
        echo -n "   "
        grab https://github.com/malbanGit/Vide/raw/master/C/Linux32/bin/cc1 ; echo " ; chmod +x ./cc1"
        echo "and issue this command again."
        exit 1
      else
        echo "Scanning your disk for \"cc1\" from the Vide IDE:"
        ( locate cc1|grep -i vide|grep cc1$|fgrep -v ._cc1 ; locate cc1|grep -i 6809|grep cc1$|fgrep -v ._cc1 ) | tee /tmp/cc1.$$.log
        if [ -s /tmp/cc1.$$.log ] ; then
            echo "You can try copying the most recent one for this OS to this directory."
        else
            if [ X`which wine` = X ] ; then
                echo "Since none were found, consider installing wine, then fetch gcc6809.exe by issuing the command:"
            else
                echo "Since none were found, and wine appears to be installed, try fetching gcc6809.exe by issuing the command:"
            fi
            grab https://github.com/malbanGit/Vide/raw/master/C/Win32/bin/gcc6809.exe
        fi
        rm -f /tmp/cc1.$$.log
        exit 1
      fi
  fi
  GCC="$BINDIR/cc1"
  if [ ! -f $GCC ] ; then
    GCC="wine gcc6809.exe"
    if   [ X"\`which wine\`" != X"" ] ; then
      if [[ "`arch`" == "arm"* ]] ; then
        echo "gcc6809: wine is not installed. You will also need something like pi386 to enable wine to work."
      else
        echo "gcc6809: wine is not installed. Either install it or remove gcc6809.exe"
      fi
      exit 1
    fi
  fi
  if [ ! -f $BINDIR/stabs ] ; then
    ( cd $BINDIR ; make stabs > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/as6809 ] ; then
    ( cd $BINDIR ; make as6809 > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/aslink ] ; then
    ( cd $BINDIR ; make aslink > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/aslib ] ; then
    ( cd $BINDIR ; make aslib > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/copt ] ; then
    ( cd $BINDIR ; make copt > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/srec2bin ] ; then
    ( cd $BINDIR ; make srec2bin > /dev/null 2> /dev/null )
  fi
  if [ ! -f $BINDIR/memimage64k ] ; then
    ( cd $BINDIR ; make memimage64k > /dev/null 2> /dev/null )
  fi
}
compile () {
  for arg in "$@"; do
    if [[ "$r" == "y" ]] ; then
      if [[ "$v" == "y" ]] ; then
        echo $GCC -quiet -fno-builtin-printf -o `basename $arg .c`.asm -g -O3 -mint16 -fPIC $arg
      fi
      $GCC -quiet -fno-builtin-printf -o `basename $arg .c`.asm -g -O3 -mint16 -fPIC $arg
      RC=$?
    else
      if [[ "$v" == "y" ]] ; then
        echo $GCC -quiet -fno-builtin-printf -o `basename $arg .c`.asm -g -O3 -mint16 $arg
      fi
      $GCC -quiet -fno-builtin-printf -o `basename $arg .c`.asm -g -O3 -mint16 $arg
      RC=$?
    fi
    if [ $RC != 0 ] ; then
        exit $RC
    fi
    #if [[ "$v" == "y" ]] ; then
    #  echo rm -f `basename $arg .c`.s
    #fi
    #rm -f `basename $arg .c`.s
    if [[ "$v" == "y" ]] ; then
      echo $BINDIR/stabs $arg \> `basename $arg .c`.s
    fi
    $BINDIR/stabs $arg > `basename $arg .c`.s
    RC=$?
    if [ $RC != 0 ] ; then
      rm -f `basename $arg .c`.s
      exit $RC
    fi
    if [[ "$v" == "y" ]] ; then
      #####echo mv `basename $arg .c`.s `basename $arg .c`.asm
      $BINDIR/copt $BINDIR/peepholer/6809-gcc < `basename $arg .c`.s > `basename $arg .c`.asm
    fi
    #####mv `basename $arg .c`.s `basename $arg .c`.asm
    $BINDIR/copt $BINDIR/peepholer/6809-gcc < `basename $arg .c`.s > `basename $arg .c`.asm
    RC=$?
    if [ $RC != 0 ] ; then
      rm -f `basename $arg .c`.s
      exit $RC
    fi
    if [[ "$v" == "y" ]] ; then
        #####diff `basename $arg .c`.s `basename $arg .c`.asm
        :
    fi
  done
}
assemble () {
    object="$1"
    shift
    for arg in "$@"; do
      if [[ "$v" == "y" ]] ; then
        echo $BINDIR/as6809 -l -o `basename $arg .asm`.o $arg
      fi
      $BINDIR/as6809 -l -o `basename $arg .asm`.o $arg
      RC=$?
      if [ $RC != 0 ] ; then
        rm -f `basename $arg .asm`.o
        exit $RC
      fi
      ENTRYPT=( $(fgrep " _main:" `basename $arg .asm`.lst) )
      if [ "${ENTRYPT}" != "" ] ; then
          # hint for disassembler
          if [[ "$v" == "y" ]] ; then
              echo "Entry point for program is ${ENTRYPT}"
          fi
          echo "code ${ENTRYPT}" > `basename $arg .asm`.dat
          #echo "data 0000-000B"
          echo "label ${ENTRYPT} Main" >> `basename $arg .asm`.dat
          
      fi
      if [[ "$d" == "n" ]] ; then
        # keep the .lst file if -d option
        rm -f `basename $arg .asm`.lst
      fi
    done
}
link () {
    object="$1"
    shift
    args="-s -o $object.s19"
    for arg in "$@"; do args="${args} `basename $arg .asm`.o"; done
    if [[ "$v" == "y" ]] ; then
      echo $BINDIR/aslink $args
    fi
    $BINDIR/aslink $args
    RC=$?
    # unfortunately missing symbols only cause warnings and exit with RC=0 :-(
    if [ $RC != 0 ] ; then
      rm -f $object.s19
      exit $RC
    fi
    if [[ "$v" == "y" ]] ; then
      echo $BINDIR/srec2bin -q $object.s19 $object.bin
    fi
    $BINDIR/srec2bin -q $object.s19 $object.bin
    if [[ "$v" == "y" ]] ; then
      echo Binary file $object.bin can be loaded at 0000
      echo $BINDIR/memimage64k -q -o $object.mem $object.bin @0000 $BINDIR/sbug.bin @F800
    fi
    $BINDIR/memimage64k -q -o $object.mem $object.bin @0000 $BINDIR/sbug.bin @F800
}

check

# More safety, by turning some bugs into errors.
# Without `errexit` you don't need ! and can replace
# ${PIPESTATUS[0]} with a simple $?, but I prefer safety.
####set -o errexit -o pipefail -o noclobber -o nounset
set -o pipefail -o nounset

# -allow a command to fail with !'s side effect on errexit
# -use return value from ${PIPESTATUS[0]}, because ! hosed $?
! getopt --test > /dev/null 
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
    echo I\'m sorry, `getopt --test` failed in this environment.
    exit 1
fi

# option --output/-o requires 1 argument
LONGOPTS=nolink,debug,pic,output:,verbose
OPTIONS=cdro:v

# -regarding ! and PIPESTATUS see above
# -temporarily store output to be able to check for errors
# -activate quoting/enhanced mode (e.g. by writing out “--options”)
# -pass arguments only via   -- "$@"   to separate them correctly
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
    # e.g. return value is 1
    #  then getopt has complained about wrong arguments to stdout
    exit 2
fi
# read getopt's output this way to handle the quoting right:
eval set -- "$PARSED"

d=n v=n c=n r=n outFile=
# now enjoy the options in order and nicely split until we see --
while true; do
    case "$1" in
        -h|--help)
            echo "syntax: gcc6809 [-o file.s19] [-c] file1.c file2.c ..."
            exit 0
            ;;
        -d|--debug)
            d=y
            shift
            ;;
        -v|--verbose)
            v=y
            shift
            ;;
        -r|--pic)
            # relocatable objects
            v=y
            shift
            ;;
        -c|--nolink)
            c=y
            shift
            ;;
        -o|--output)
            outFile="$2"
            shift 2
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "Programming error"
            exit 3
            ;;
    esac
done

# handle non-option arguments
if [[ $# -lt 1 ]]; then
    echo "$0: At least one file.c is required."
    echo ""
    echo "syntax: gcc6809 [-o file.s19] [-c] file1.c file2.c ..."
    exit 1
fi

if [[ "$outFile" == "" ]] ; then
  outFile="`basename $1 .c`"
else
  if [[ "$c" == "y" ]] ; then
    echo "-o is not allowed if -c is given: \"-c\" means do not link, but \"-o\" is the output of the link stage!"
    exit 1
  fi
fi
if [[ "$d" == "y" ]] ; then
  echo "output memory image will be $outFile.mem"
fi
objects=""
for infile in $@ ; do
  if [[ "$d" == "y" ]] ; then
      echo "verbose: $v, debug: $d, in: $infile"
  fi
  objects="${objects} `basename $infile .c`.asm"
  compile $infile
done
assemble $outFile $objects
if [[ "$c" != "y" ]] ; then
  link $outFile $objects
fi
