#! /bin/sh -norc
#.f77-style shell script to compile and load fortran, C, and assembly codes
#.	usage:	f77 [-g] [-O] [-o absfile] [-c] files [-l library]
#.		-o objfile	Override default executable name a.out.
#.		-c		Do not call linker, leave relocatables in *.o.
#.		-a		Use automatic variables as default
#.		-GD             uncomment D comments
#.		-S		leave assembler output on file.s
#.		-l library	(passed to ld).
#.              -Wl,option      pass option to the linker
#.		-u		complain about undeclared variables
#.		-w		omit all warning messages
#.		-w66		omit Fortran 66 compatibility warning messages
#.             -cf opt          pass options to the C compiler
#              -cpf opt         pass options to cpp
#.             -f2c opt         pass options to f2c 
#.             --keepC          keep original C files for better debugging
#.             --commainsert    insert commatas between continued lines of
#.                              common blocks if missing - might fail!
#.             --elf            write elf code (linux only)
#.             --aout           write aout code (linux only)
#.		files		FORTRAN source files ending in .f .
#.				C source files ending in .c .
#.				Assembly language files ending in .s .
#.				efl source files ending in .e .
#.		-I includepath	passed to C compiler (for .c files)
#.		-Ntnnn		allow nnn entries in table t
#.		-cpp -Dxxx	pipe through cpp
#.------------------------
#.based on the f77 script coming with slackware.
#.modifications for f77reorder and some others 
#.wwc@mit.edu (Wolfgang Wander)

# PATH=${exec_prefix}/bin:/bin:/usr/bin:/usr/local/bin

function erroutput {
  matchable=$(echo $2 | sed 's/\([./]\)/\\\1/g')
  gawk '
  BEGIN {
    while( getline < "'$1'" ) {
      realline[$1] = $2
      realfile[$1] = $3
}
  }
  /(^Warning)|(^Error)/ {
    if( 0 != match( $0, " line [0-9]+") ) {
      matstr = substr( $0, RSTART, RLENGTH );
      split( matstr, arr );
      line   = arr[2];
      astr   = substr( $0, 1, RSTART-1 );
      bstr   = substr( $0, RSTART+RLENGTH)
      if( match( bstr, "'$matchable'") ) {
	cstr = bstr
	bstr = substr(cstr, 1, RSTART-1) "" realfile[line] "" \
	 substr( cstr, RSTART+RLENGTH)
      }
      printf "%s line %d%s\n", astr, realline[line], bstr > "/dev/stderr"
    } else
      print $0  > "/dev/stderr"
      next
  }
  /'$matchable'/ {
    match( $0, "'$matchable'") 
    bstr = substr($0, 1, RSTART-1) "'$3'" \
     substr( cstr, RSTART+RLENGTH)
    print bstr > "/dev/stderr"
    next	 
  }

  {   print $0  > "/dev/stderr"
  }
  ' < $4
  
}

function debugcorrect {
  matchable=$2
  cfile=$4
  gawk '
  BEGIN {
    while( getline < "'$linefile'" ) {
      realline[$1] = $2
      realfile[$1] = $3
    }
  }
  /^#line/ {

    line=$2
    len3=length($3)
    filename=substr($3,2,len3-2)
    if ( filename == "'$matchable'" ) {
      printf "#line %d \"%s\"\n" , realline[line], realfile[line]
    } else {
      print $0
    }
    next
  }
  { print $0 }
    ' < $cfile > /tmp/gc.$$
    mv /tmp/gc.$$ $cfile
}

function fortrancompile( ) {

  # -------- build some filenames ---------
  case "$1" in			# get the extension
    *.f) f=".f";; 
    *.F) f=".F";; 
  esac
  b=`basename $1 $f`		# get the filename without the extension
  d=`dirname $1`		# and the directory name
  fname=${1##*/}                # and the filename with extension
  tmpbod=/tmp/f2ctmp$$_$b	# a temp file
  tmpfile=${tmpbod}.f
  errfile=${t}$$.err		# collected error output
  linefile=${t}$$.lines		# line number file

  # --------- clean up after exit ----------
  trap "rm -f ${tmpbod}.* $linefile; exit 4" 0

  # --------- cpp handling --------
  if [ -z "$CPP" ]; then	
    cppc=/bin/cat
  else
    cppc="$CPP $CPPOFLAGS $CPPFLAGS"
  fi
  
  # --------- 'D'ebug comments --------
  if [ $DCOMMENTS = YES ]; then	# Either replace ^D Comments with C
    DCOM="-e s/^[dD]/C/"
  else
    DCOM="-e s/^[dD]/ /"	# or enable this lines
  fi

  # --------- which debug output is generated? --------
  if [ "$G" = -g ]; then	# debug specified
    if [ "$KEEPC" = y ]; then	# C files kept. Debug in C code
      F2CFL="$F2CFLAGS"
    else
      F2CFL="$F2CFLAGS -g"	# otherwise generate f77 debug code
    fi
  else
    F2CFL="$F2CFLAGS"		# no debug info
  fi

  # --------- pass1. Call some sed lines and f77reorder --------
  rm -f $errfile
  if [ -z "$CPP" ]; then
    # correct TAB-DIGIT line continuation 
    ( sed -e 's/^	[0-9]/     >   /' "$DCOM" $d/$fname || \
     echo 'sed' > $errfile ) | \
    # and call f77reorder to correct some f77non-standards 
    ( f77reorder $COMMAINSERT \
     --file $fname --line $linefile > $tmpfile || \
     echo 'f77reorder' > $errfile )
  else
    # replace every fortran include statement by a cpp include statement
    ( sed  's/^[	 ]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][	 ]*['\''"]\([^'\'']*\)['\''"].*$/#include "\1"/' $d/$fname  || \
     echo sed > $errfile ) | \
     # call cpp
    ( $cppc || echo cpp >$errfile ) | \
     # correct TAB-DIGIT line continuation 
    ( sed -e 's/^	[0-9]/     >   /' $DCOM || \
     echo sed > $errfile ) | \
     # and call f77reorder to correct some f77non-standards 
    ( f77reorder $COMMAINSERT  \
     --file $fname --line $linefile >$tmpfile || \
     echo f77reorder > $errfile )
  fi

  # -------- check for errors -----------
  if [ -r $errfile ]; then
    echo 'error in ' $(cat $errfile)
    exit 1
  fi

  # -------- pass1. Call f2c ----------
  oldpwd=`pwd`
  cd $d >/dev/null		# change into the files directory
  trap "rm -f $tmpfile $linefile $errfile; exit 4" 0
  $F2C -d/tmp $F2CFL -I$d $tmpfile 2> $errfile
  err=$?

  # -------- print out possible errors and warnings with correct line
  # -------- numbers -------

  erroutput $linefile $tmpfile $d/$fname $errfile
  case $err in 0);;		# serious errors -> terminate
    *) 
       trap '' 0
       rm -f ${tmpbod}.* $linefile $errfile
       exit 5;; 
  esac
  
  # -------- pass3. Run gcc on the translated c file ----------

  mv ${tmpbod}.c $b.c		# the c file must reside in this directory

  if [ "$G" = -g -a "$KEEPC" != y ]; then # correct the debug lines
    debugcorrect $linefile $tmpfile $d/$fname $b.c
  fi
  rm -f $tmpfile $linefile $errfile

  if [ -f ${tmpbod}.P ]; then 
    mv ${tmpbod}.P $b.P; 
  fi

  case $? in 
    0);; 
    *) rm -f $b.c ; exit 5;; 
  esac

  trap "rm -f $s ; exit 4" 0
  $CC $CPPFLAGS -c $COUTFLAGS $CFLAGS $b.c 2>$s	# call gcc
  rc=$?

  # some warnings are obsolete
  sed '/parameter .* is not referenced/d;/warning: too many parameters/d' $s 1>&2 
  case $rc in 
    0);; 
    *) exit 5;; 
  esac
  ## keep c file in case of debug mode
  if test "$KEEPC"x = x; then
    rm -f $b.c
  fi
  OFILES="$OFILES $d/$b.o"
  case $cOPT in 
    1) cOPT=2;; 
  esac
  ## insert directory order
  cd $oldpwd >/dev/null
  if [ "$cOPT" -eq 0 -a "$OUTF" != "a.out" ]; then
    if ! [ $d/$b.o -ef $OUTF ]; then
      mv $d/$b.o $OUTF
    fi
  fi
}

CSTDOPTS=""
CELFTYPE="NONE"
CAOUTTYPE="NONE"
COUTFLAGS=""

CC=${CC_f2c:-"/usr/bin/cc $CSTDOPTS"}
s=/tmp/stderr_$$
pwd=$(pwd)
t=/tmp/f77_$$
EFL=${EFL:-/v/bin/efl}
EFLFLAGS=${EFLFLAGS:-'system=portable deltastno=10'}
F2C=${F2C:-}
F2CFLAGS=${F2CFLAGS:='-ARw8 -Nn802'}
rc=0
lib=/lib/num/lib.lo
trap "rm -f $s ; exit \$rc" 0
OUTF=a.out
cOPT=1
G=
KEEPC=
COMMAINSERT=
CPP= 
CPPFLAGS=
CPPOFLAGS=
DCOMMENTS=YES
LFLAGS=
# set -- `getopt cD:gI:N:Oo:Suw6 "$@"`
case $? in 
  0);; *) 
  exit 1;; 
esac
CCFLAGS=
while test X"$1" != X--; do
  case "$1"	in
    --h*|-h*|-\?)
		  awk '/^#\./ {print "  " substr($0,3)}' < $0
		  exit 1
		  ;;
    -c)	cOPT=0
	shift
	;;
    
    -cf)	
	 CFLAGS="$CFLAGS $2"        # wwc
	 shift 2
	 ;;
    --commainsert)	
		   COMMAINSERT="$1"   # wwc
		   shift 1
		   ;;
    -cpf)	
	  CPPOFLAGS="$CPPOFLAGS $2"  # wwc
	  shift 2
	  ;;
    --elf)  
	   COUTFLAGS="$CELFTYPE"      # wwc 
	   shift
	   ;;
    --aout) 
	    COUTFLAGS="$CAOUTTYPE"     # wwc 
	    shift
	    ;;
    -f2c)   
	  F2CFLAGS="$F2CFLAGS $2"    # wwc 
	  shift 2
	  ;;
    -a)    
	F2CFLAGS="$F2CFLAGS -a"    # wwc 
	shift 
	;;
    -D)	
	CPPFLAGS="$CPPFLAGS -D$2"
	shift 2
	;;

    -D*)
	 CPPFLAGS="$CPPFLAGS $1"
	 shift 1
	 ;;

    -g)	
	CFLAGS="$CFLAGS -g"
	CCFLAGS="$CCFLAGS -g"
	F2CFLAGS="$F2CFLAGS -c"
	G="-g"
	shift;;

    --keepC) 
	     KEEPC=y
	     shift;;

    -I)	
	CCFLAGS="$CCFLAGS -I$2"
	CPPFLAGS="$CPPFLAGS -I$2"
	shift 2
	;;
    
    -I*)
	 CCFLAGS="$CCFLAGS $1"
	 CPPFLAGS="$CPPFLAGS $1"
	 shift 1
	 ;;
    
    -Wl,*)
	   LFLAGS="$LFLAGS $1"
	   shift 1
	   ;; 
    
    -o)	
	OUTF=$2
	shift 2
	;;
    
    -O|-O?)
	    CCFLAGS="$CCFLAGS $1"
	    shift
	    ;;
    
    -u)	
	F2CFLAGS="$F2CFLAGS -u"
	shift
	;;
    
    -w)	
	F2CFLAGS="$F2CFLAGS -w"
	case $2 in 
	  -6) 
	      F2CFLAGS="$F2CFLAGS"66; 
	      shift
	      case $2 in 
		-6) shift
		    ;; 
	      esac
	      ;; 
	esac
	shift
	;;
    
    -N)	F2CFLAGS="$F2CFLAGS $1""$2"
	shift 2
	;;
    
    -GD)	
	 DCOMMENTS=NO
	 shift 1
	 ;;
    
    -N*|-C)	
	    F2CFLAGS="$F2CFLAGS $1"
	    shift 1
	    ;;
    
    -cpp)	
	  CPP="/lib/cpp -traditional"
	  shift 1
	  ;;
    
    -S)	
	CFLAGS="$CFLAGS -S"
	cOPT=0
	shift
	;;
    
    -*)
	echo "invalid parameter $1" 1>&2
	echo 'type f77 -? to get a list of options.'
	shift
	;;
    
    *)	
       set -- -- $@
       ;;
  esac
done
shift

while test -n "$1"; do
  case "$1"	in
    *.[fF])
	    fortrancompile $1
	    shift
	    ;;
    *.e) 
	 b=`basename $1 .e`
	 ## wwc insert f77reorder
	 $EFL $EFLFLAGS $1 | f77reorder >$b.f
	 case $? in 
	   0);; 
	   *) exit;; 
	 esac
	 $F2C $F2CFLAGS $b.f
	 case $? in 
	   0);; 
	   *) exit;; 
	 esac
	 $CC -c $COUTFLAGS $CFLAGS $b.c
	 case $? in 
	   0);; 
	   *) exit;; 
	 esac
	 OFILES="$OFILES $b.o"
	 rm $b.[cf]
	 case $cOPT in 
	   1) cOPT=2;; 
	 esac
	 shift
	 ;;
    *.s)
	 echo $1: 1>&2
	 OFILE=`basename $1 .s`.o
	 ${AS:-/usr/bin/as} -o $OFILE $AFLAGS $1
	 case $? in 
	   0);; 
	   *) exit;; 
	 esac
	 OFILES="$OFILES $OFILE"
	 case $cOPT in 
	   1) cOPT=2;; 
	 esac
	 shift
	 ;;
    *.c)
	 echo $1: 1>&2
	 OFILE=`basename $1 .c`.o
	 $CC -c $COUTFLAGS $CFLAGS $CCFLAGS $CPPFLAGS $1
	 rc=$?
	 case $rc in 
	   0);; 
	   *) exit;; 
	 esac
	 OFILES="$OFILES $OFILE"
	 case $cOPT in 
	   1) cOPT=2;; 
	 esac
	 shift
	 ;;
    *.o)
	 OFILES="$OFILES $1"
	 case $cOPT in 
	   1) cOPT=2;; 
	 esac
	 shift
	 ;;
    -l)
	OFILES="$OFILES -l$2"
	shift 2
	case $cOPT in 
	  1) cOPT=2;; 
	esac
	;;
    -l*)
	 OFILES="$OFILES $1"
	 shift
	 case $cOPT in 
	   1) cOPT=2;; 
	 esac
	 ;;
    -o)
	OUTF=$2; shift 2;;
    *)
       OFILES="$OFILES $1"
       shift
       case $cOPT in 
	 1) cOPT=2;; 
       esac
       ;;
  esac
done

case $cOPT in 
  2) $CC $LFLAGS $COUTFLAGS $CFLAGS -o $OUTF $OFILES -lf2c -lf77 -lm;; 
esac
rc=$?
trap "" 0
rm -f $s
exit $rc

