#!/bin/sh
#**************************************************************
# CSTART - driver code generator
#**************************************************************
Version="Ver 1.3"
Author="Seongjai Kim"
Email="skim@ms.uky.edu"
Date="[1;7mCopyright 2000[m"
WARNING="[1;7mWARNING[m"
NOTE="${WARNING}: This program cannot be used for commercial purposes."

echo "[1;7mCSTART $Version[m: driver code generator
$Date, ${Author}: $Email
$NOTE" 1>&2

UNAME="`uname`"
if [ "$UNAME" = "HP-UX" -o "$UNAME" = "HPUX" ]; then
   SN='\\n'
else
   SN='\n'
fi

#-------------------------------------------
#--- Default Setting -----------------------
#-------------------------------------------

SETFILE=SET_file
MAINCPP=Main.cpp
IOSETC=IOset.c
READDATA=ReadDATA.c
verbose=1
LEVEL=0
INLEVEL=0

PROGRAM=
AUTHOR=
DATE=
COMMENT=
ARRAY=A
NARR=0
ATYPE=double
VTYPE=$ATYPE
DATA="DATA"
NDATA="n1*n2"
DTYPE=float
DATAEXT="@"
WKSP="wksp"
NWKSP=0
HEADERS=
CALLS=
CDATA=

INPROGRAM=0
INAUTHOR=0
INDATE=0
INCOMMENT=0
INARRAY=0
INNARR=0
INATYPE=0
INVTYPE=0
INDATA=0
INNDATA=0
INDTYPE=0
INDATAEXT=0
INWKSP=0
INNWKSP=0
INHEADERS=0
INCALLS=0
INCDATA=0

SPECIAL="array arr narr narray atype vtype data datafile ndata dtype dataext"
SPECIAL="$SPECIAL wksp nwksp nws header headers call calls cdata constdata"
SPECIAL="$SPECIAL program programme comment comments"
SPECIAL="$SPECIAL author programer programmer date day"

README="CSTART.README"
CSPARS="CSTART.PARS"
Default="[1;7mDefault[m"
WARNING="[1;7mWARNING[m"

#-------------------------------------------
#--- Define Functions ----------------------
#-------------------------------------------

#******************** self documentation **********************
DOC () { echo "
 CSTART - provides a quick start-up code

 cstart \"setfile\" [optional parameters] | ....

 Optional Parameters:

     set[file]=$SETFILE       the input setfile
     defa[ult]                to use the above degault file name
     main[file]=$MAINCPP      the main file name
     io[file]=$IOSETC         the IO-routine file name
     read[file]=$READDATA    the READDATA routine name
     ve[rbose]=$verbose              for diagnostic print on stdout
     -h*|help|opt*)           for this message

 General:
     Let's assume that you want to find the best-fitting quadratic
     polynomial for a given set of data, by using the QR factorization.
     You may download a code for the QR method from one of public sites.
     Still you have write (1) an Input/Output routine to read the data
     and set appropriate algorithm parameters, (2) a converter with
     which your data will fit into the QR code, (3) the main routine
     to combine all the components together, and (4) the makefile
     that compiles and links the objects for the target executable.
     In industrial applications, it is indispensable to write a converter
     (or revise an old code) for the data to fit the solution method.
     I will assume that you already got the converter, somehow.

     The purpose of CSTART is to generate touch-free routines for the
     steps (1) and (3).  If your data-format and/or algorithm parameters
     are newly given or changed, you may control the new computional
     task by setting/editing some of parameters in the setfile or
     re-run CSTART to generate new driver routines for the new set
     of parameters and data.  In the case of re-run, the old drive
     routines will be moved to backup files and new routines will
     be generated.  If you have to touch the generated routines,
     now you should spend a certain amount of time on the new code;
     it is sometimes time-consuming and cumbersome.  So \"touch-free
     generation\" is very important and we will se it in CSTART.

     For the last step, I will provide an automatic makefile maker,
     called \"mkmk\", written in shell. The generated Makefile is
     again touch-free, for various Unix systems.
       
 SET-File:
     The setfile can include most of information not only for CSTART
     but also for the execuable.  Other information can be set in
     infofiles.  The following is an example setfile:

         nt=100 at=0.0 bt=1.0
         nx=65 ny=65 nz=65
         ax=0.0 bx=1.0
         ay=0.0 by=1.0
         az=0.0 bz=1.0

         itmax=500
         tol=1.e-5
         message=Successful-Finale

         idpde=0 idsol=1
         level=2 idata=1

         program=\"$PROGRAM\"
         author=\"$AUTHOR\"
         date=\"$DATE\"
         comment=\"$COMMENT\"
         array=\"$ARRAY\"      
         narr=\"$NARR\"
         atype=$ATYPE   	: to open \"atype array[narr]\"
         vtype=$VTYPE   	: to open \"atype array[narr]\"
         data=DATA
         ndata=$NDATA
         dtype=$DTYPE       	: to open \"dtype data[ndata]\"
         dataext=\"$DATAEXT\"
         wksp=$WKSP
         nwksp=\"$NWKSP\"       	: to open \"atype wksp[nwksp]\"
         Headers=$HEADERS
         Calls=\"$CALLS\"
         ConstData=\"$CDATA\"

     The order, letter-cases, and format of the parameters do not
     matter; you may choose a subset of it or add more parameters.
     The problem is: How can CSTART recognize the right type of variables?
     Here I set the convention: if right-hand side (initialization)
     of the setting starts with [-]?[.]?[0-9], then it is an integer
     or a float variable.  Again, if the right-hand side includes \".\",
     it is a float.  So, for example, nt, tol, and message will be
     recognized as an int, float, and char variable, respectively.
     If you want to set a float variable \"zero\" with intial value 0,
     you have to set \"zero=0.0\" or \"zero=0.\", not like \"zero=0\".
     For a char or string variable, you do not have to place the
     quotation mark for the initial value, but it should be connected
     as one field.

     Exception: The last 17 parameters in the above setfile will be
     considered as char or symbolic setting and they can be located
     anywhere in the setfile.  They will be used only to produce the
     driver routines, which implies the resulting executable will ignore
     them. If you do not want to set, then erase the line from the
     setfile or set the empty initial value as in ConstData=\"\".

 DATA-Files:
     If your project includes reading datafiles addtion to the
     setfile, you have to give CSTART a certain form of information
     for the \"infofiles\" and \"datafiles\"(=infofile\$dataext).
     Here the dataext=\"$DATAEXT\" at default and you may choose your
     convenient name for infofile and datafile.  For example, if you
     choose \"DATA\" and \"DATA.ascii\" for infofile and datafile,
     respectively, then you have to set dataext=\".ascii\" somewhere
     in the setfile.  Each infofile should include information for
     the geometry of the data saved in datafile; use \"n1\" and \"n2\"
     for the number of rows and the number of columns, respectively.
      

 Note:
     If you do not know how to start CSTART yet, just give it
     a setfile name.  Then, it will give you the default settings
     in the file you chose.  Now you can customize the setfile
     for your own purpose and re-run CSTART.

     For more details, look at the user's manual.
"
}
#***************** end self doc *******************************
#**************************************************************
DFTSET () {
echo "nt=100
nfield=2
at=0.0 bt=1.0

nx=65 ny=65 nz=65

ax=0.0 bx=1.0
ay=0.0 by=1.0
az=0.0 bz=1.0

itmax=500
tol=1.e-5

idpde=0
idsol=1
level=2
idata=1
n1=10 n2=2

array=$ARRAY
narr=$NARR
atype=$ATYPE
data=$DATA
ndata=\"$NDATA\"
dtype=$DTYPE
dataext=\"$DATAEXT\"
nwksp=\"$NWKSP\"
Headers=\"A00.h\"
Calls=\"A11.h\"
ConstData="
}
#**************************************************************
MAINHEAD () {
echo "/*************************************/
/*** Main.cpp: generated by CSTART ***/
/*** For details,  skim@ms.uky.edu ***/
/*** `date '+%a %h %d, %y;   %r'` ***/
/*************************************/

#include <iostream>
#include <cstring>
using namespace std;
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#define  MAX_LEN 80"
}
#**************************************************************
F77EXTERN () { echo "/*** An example of declaring F77 routine ***/
#if defined (_IBMR2) || defined (AIX) || defined (hpux)
   extern \"C\" void f77name(int&nx,float&ax,float*array);
#else
   extern \"C\" void f77name_(int&nx,float&ax,float*array);
#endif

/*** An example of calling F77 routine ***/
#if defined (_IBMR2) || defined (AIX) || defined (hpux)
   f77name(nx,ax,array);    // from C++
   f77name(&nx,&ax,array);  /* from C */
#else
   f77name_(nx,ax,array);   // from C++
   f77name_(&nx,&ax,array); /* from C */
#endif
"
}
#**************************************************************
LASTINFORM () { echo "
Now, you may try
    [1mmkmk[0m to generate Makefile
    [1mmake[0m to compile and generate the executable
    [1mxx[0m   to run the program"
}
#**************************************************************
IOHEAD () {
echo "/*** IO utility for reading setfile ***/
/*** Gererated by Dr. Kim's CSTART  ***/

#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#if defined(_IBMR2) || defined (AIX) || defined(hpux)
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#define MAX_LEN 80"
}
#**************************************************************
DATAHEAD () {
echo "/*** ReadDATA: for reading datafile ***/
/*** Gererated by Dr. Kim's CSTART  ***/

#include <stdio.h>
#include <strings.h>"
}
#**************************************************************

#-------------------------------------------
#--- Read Stdin Optional Parameters --------
#-------------------------------------------
case $# in
    0)
        DOC | more -20 1>&2; exit 1 ;;
    *)
        ARGS="`echo $* | sed -e 's/\ =/=/g' -e 's/=\ /=/g' -e 's/\"//g'`"
        for i in $ARGS
        do
            case $i in
            set*=*) SETFILE=`echo $i | sed 's/set.*=//'` ;;
            main*=*) MAINCPP=`echo $i | sed 's/main.*=//'` ;;
            io*=*)   IOSETC=`echo $i | sed 's/io.*=//'` ;;
            read*=*) READDATA=`echo $i | sed 's/read.*=//'` ;;
            ve*=*)   verbose=`echo $i | sed 's/ve.*=//'` ;;
            -h*|help|opt*) DOC | more -20 1>&2; exit 1 ;;
            defa*) ;;
            *) SETFILE=$i ;;
            esac
        done
;;
esac

#-------------------------------------------
#--- Basic setting for $SETFILE -----------
#-------------------------------------------

if [ $verbose -ne 0 ] ; then
   echo "
setfile=$SETFILE" 1>&2
fi

if [ ! -f $SETFILE ]; then
   echo "No \"$SETFILE\" exists." 1>&2
   echo -n "Save default setfile (Y/n)? " 1>&2
   read aaa
   if [ "$aaa" != "n" -a "$aaa" != "N" ]; then
      DFTSET > $SETFILE
   else
      echo "Forced to Quit!" 1>&2; exit 1;
   fi
fi

echo -n "
Edit \"$SETFILE\" (N/y)? " 1>&2;
read aaa
if [ "$aaa" = "y" -o "$aaa" = "Y" ]; then
   vi $SETFILE
fi

#-------------------------------------------
#--- Read the $SETFILE --------------------
#-------------------------------------------

PARS="`cat $SETFILE | sed -e 's/\ =/=/g' -e 's/=\ /=/g' -e 's/\"//g'`"
npar=`echo $PARS | wc -w`
if [ $npar -eq 0 ]; then
   echo "$SETFILE is empty." 1>&2
   echo "Forced to Quit!" 1>&2; exit 1
fi

SETVAR=
MAINVAR=
CHARVAR=
FSCANF=
IOCHAR=

for par in $PARS; do
   t1="`echo $par | sed -e 's/=.*//'`"
   t2="`echo $par | sed -e 's/.*=//'`"
   if [ "$t1" = "ierr" ]; then
      echo "\"ierr\" cannot be a parameter in $SETFILE" 1>&2
      echo "Forced to Quit!" 1>&2; exit 1
   elif [ "$t1" = "level" ]; then
      INLEVEL=1; LEVEL=$t2
   fi

   t1c="`echo $t1 | tr A-Z a-z`"

   case $t1c in
   program*) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         PROGRAM="$t2"; INPROGRAM=1
      fi ;;
   author|program*er) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         AUTHOR="$AUTHOR $t2"; INAUTHOR=1
      fi ;;
   date|day) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         DATE="$t2"; INDATE=1
      fi ;;
   comment*) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         COMMENT="$COMMENT $t2"; INCOMMENT=1
      fi ;;
   arr|array) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         ARRAY="$t2"; INARRAY=1
      fi ;;
   narr|narray) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         NARR="$t2"; INNARR=1
      fi ;;
   a*type) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         ATYPE="`echo $t2 | sed -e 's/_/\ /g' -e 's/\./\ /g'`"; INATYPE=1
      fi ;;
   v*type) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         VTYPE="`echo $t2 | sed -e 's/_/\ /g' -e 's/\./\ /g'`"; INVTYPE=1
      fi ;;
   data|datafile) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         DATA="$t2"; INDATA=1
      fi ;;
   ndata) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         NDATA="$t2"; INNDATA=1
      fi ;;
   d*type) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         DTYPE="`echo $t2 | sed -e 's/_/\ /g' -e 's/\./\ /g'`"; INDTYPE=1
      fi ;;
   dataext*) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         DATAEXT="$t2"; INDATAEXT=1
      fi ;;
   wksp) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         WKSP="$t2"; INWKSP=1
      fi ;;
   nws|nwksp) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         NWKSP="$t2"; INNWKSP=1
      fi ;;
   header*) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         HEADERS="$t2"; INHEADERS=1
      fi ;;
   call|calls) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         CALLS="$t2"; INCALLS=1
      fi ;;
   cdata|const*data) IOCHAR="$IOCHAR $t1"; type=char; field=s
      if [ "$t2" != "" ]; then
         CDATA="$t2"; INCDATA=1
      fi ;;
   *)
      idnum=`echo $t2 | awk '{if($1~/^[-]?[.]?[0-9]/){print 1} else {print 0}}'`
      if [ $idnum -eq 1 ]; then
         t3="`echo $t2 | sed -e 's/\..*//'`"
         if [ "$t2" = "$t3" ]; then
            type=int;   field=d
         else
            type=VTYPE; field=g
         fi
      else
         type=char; field=s
      fi

      if [ "$MAINVAR" = "" ]; then
         MAINVAR="$type $t1"
      else
         MAINVAR="$MAINVAR $type $t1"
      fi
      ;;
   esac

   if [ "$SETVAR" = "" ]; then
      SETVAR="$type $t1"
   else
      SETVAR="$SETVAR $type $t1"
   fi
   if [ "$FSCANF" = "" ]; then
      FSCANF="$t1=%$field"
   else
      FSCANF="$FSCANF $t1=%$field"
   fi
done

if [ "$VTYPE" = "double" ]; then
   FSCANF="`echo $FSCANF | sed -e 's/\=\%g/\=\%lg/g'`"
fi

SCANVAR="`echo $SETVAR | sed -e 's/VTYPE/int/g' -e 's/char/int/g' |\
        sed -e 's/\ int\ /\,/g' | sed -e 's/int\ //g'`"

if [ "$CDATA" != "" ]; then
   CINFO="`echo $CDATA | sed -e 's/\,/\ /g' | sed -e s/$DATAEXT//g`"
fi

if [ "$IOCHAR" != "" ]; then
   TMP=
   for i in $IOCHAR; do
      again=0
      for j in $TMP; do
         if [ "$j" = "$i" ]; then
            again=1
         fi
      done
      if [ $again -eq 0 ]; then
         TMP="$TMP $i"
      fi
   done
   IOCHAR="$TMP"
fi

#-------------------------------------------
#--- Search DATAFILE -----------------------
#-------------------------------------------

INFOFILE=
OPTINFO=

if [ "$DATAEXT" != "" -a "$DATAEXT" != "no" ]; then
   TEMP="`ls *$DATAEXT`"
   for dfile in $TEMP; do
      if [ -f $dfile ]; then
         ifile="`echo $dfile | sed -e s/$DATAEXT//`"
         again=0
         for j in $CINFO; do
            if [ "$j" = "$ifile" ]; then
               again=1
            fi
         done
         if [ $again -eq 0 ]; then
            OPTINFO="$OPTINFO $ifile"
         fi
      fi
   done
fi

NOI=`echo $OPTINFO | wc -w`
INFOFILE="`echo $OPTINFO $CINFO`"

#-------------------------------------------
#--- Check if $SETFILE is new --------------
#-------------------------------------------

if [ -f $MAINCPP ]; then
   NEWER="`ls -t $SETFILE $MAINCPP $INFOFILE`"
   NEWER="`echo $NEWER | awk '{print $1}'`"
   if [ "$NEWER" = "$MAINCPP" ]; then
      echo -n "
$SETFILE (and infofiles) has not been touched
since the last generation of $MAINCPP.
Still, do you want to regenerate $MAINCPP (Y/n)? " 1>&2
      read aaa
      if [ "$aaa" = "n" -o "$aaa" = "N" ]; then
         echo "Forced to Quit!" 1>&2; exit 1
      fi
   fi
fi

#-------------------------------------------
#--- Set from $INFOFILE --------------------
#-------------------------------------------
ALLNDATA=
ALLDATA=

if [ "$INFOFILE" != "" ]; then
   if [ $NOI -ge 2 ]; then
      if [ "`echo $SCANVAR | grep idata`" = "" ]; then
         echo "" 1>&2
         echo "You have $NOI optional datafiles." 1>&2
         echo "Set e.g. \"idata=1\" in \"$SETFILE\"." 1>&2
         echo "Forced to Quit!" 1>&2
         exit 1
      fi
   fi
   for file in $INFOFILE; do
      PARS="`cat $file | sed -e 's/\ =/=/g' -e 's/=\ /=/g' -e 's/\"//g'`"
      TMPD=; TMPN=
      for par in $PARS; do
         again=0
         t1="`echo $par | sed -e 's/=.*//'`"
         t2="`echo $par | sed -e 's/.*=//'`"
         t1c="`echo $t1 | tr A-Z a-z`"
         for j in $SPECIAL; do
            if [ "$j" = "$t1c" ]; then
               again=1
            fi
         done
         case $t1c in
            data|arr|array) TMPD="$t2"; again=1 ;;
         esac
         case $t1c in
            ndata|narr|narray) TMPN="$t2"; again=1 ;;
         esac

         if [ $again -eq 1 ]; then
            ntmp=0
            for i in $IOCHAR; do
               if [ "$i" = "$t1" ]; then
                  ntmp=1
               fi
            done
            if [ $ntmp -eq 0 ]; then
               IOCHAR="$IOCHAR $t1"
            fi
         else
            idnum=`echo $t2 | \
               awk '{if($1~/^[-]?[.]?[0-9]/){print 1} else {print 0}}'`
            if [ $idnum -eq 1 ]; then
               t3="`echo $t2 | sed -e 's/\..*//'`"
               if [ "$t2" = "$t3" ]; then
                  type=int
               else
                  type=VTYPE
               fi
            else
               type=char
            fi
            for j in $MAINVAR; do
               if [ "$j" = "$t1" ]; then
                  again=1
               fi
            done
            if [ $again -eq 0 ]; then
                MAINVAR="$MAINVAR $type $t1"
            fi
         fi
      done
      if [ "$TMPD" = "" ]; then
         TMPD=$DATA
      fi
      if [ "$TMPN" = "" ]; then
         TMPN=$NDATA
      fi

      ALLNDATA="$ALLNDATA $TMPD=$TMPN"
      ntmp=0
      for i in $ALLDATA; do
         if [ "$i" = "$TMPD" ]; then
            ntmp=1
         fi
      done
      if [ $ntmp -eq 0 ]; then
         ALLDATA="$ALLDATA $TMPD"
      fi
   done

   DEXTERN="int n1,int n2,DTYPE*${DATA},int level,int*ierr"
   DANSWER="int n1,int n2,DTYPE ${DATA}[][n2],int level,int*ierr"

   CHAR1="char*setfile,char*infofile,char*datafile"
   CHAR2="setfile,infofile,datafile"
else
   CHAR1="char*setfile"
   CHAR2="setfile"
fi

EXTERN="`echo $MAINVAR | sed -e 's/int\ /int*/g' -e 's/VTYPE\ /VTYPE*/g' \
        -e 's/char\ /char*/g' | sed -e 's/\ /\,/g'`"
MAINCALL="`echo $MAINVAR | sed -e 's/VTYPE/int/g' -e 's/\ char\ /\,/g' |\
        sed -e 's/\ int\ /\,\&/g' | sed -e 's/int\ /\&/g' -e 's/char\ //g'`"
EXTERN="$EXTERN,int*ierr"
MAINCALL="$MAINCALL,&ierr"

#-------------------------------------------
#--- Print MESSAGE -------------------------
#-------------------------------------------

echo "" 1>&2

if [ $INLEVEL -eq 0 ]; then
   echo "$WARNING: you did not set \"level\" in $SETFILE." 1>&2
  fi
if [ $INPROGRAM -eq 0 ]; then
   echo "$Default: setting Program=\"$PROGRAM\"" 1>&2
  fi
if [ $INAUTHOR -eq 0 ]; then
   echo "$Default: setting Author=\"$AUTHOR\"" 1>&2
  fi
if [ $INDATE -eq 0 ]; then
   echo "$Default: setting Date=\"$DATE\"" 1>&2
  fi
if [ $INCOMMENT -eq 0 ]; then
   echo "$Default: setting Comment=\"$COMMENT\"" 1>&2
  fi
if [ $INARRAY -eq 0 ]; then
   echo "$Default: setting Array=\"$ARRAY\"" 1>&2
  fi
if [ $INNARR -eq 0 ]; then
   echo "$Default: setting Narr=\"$NARR\"" 1>&2
  fi
if [ $INATYPE -eq 0 ]; then
   echo "$Default: setting ATYPE=\"$ATYPE\"" 1>&2
  fi
if [ $INVTYPE -eq 0 ]; then
   echo "$Default: setting VTYPE=\"$VTYPE\"" 1>&2
  fi
if [ "$INFOFILE" != "" -a "$INFOFILE" != " " ]; then
   if [ $INDATA -eq 0 ]; then
      echo "$Default: setting Data=\"$DATA\"" 1>&2
     fi
   if [ $INNDATA -eq 0 ]; then
      if [ "$OPTINFO" != "" ]; then
        echo "$Default: setting Ndata=\"$NDATA\"" 1>&2
      fi
     fi
   if [ $INDTYPE -eq 0 ]; then
      echo "$Default: setting DTYPE=\"$DTYPE\"" 1>&2
     fi
   if [ $INDATAEXT -eq 0 ]; then
      echo "$Default: setting DataExt=\"$DATAEXT\"" 1>&2
     fi
fi
if [ $INWKSP -eq 0 ]; then
   echo "$Default: setting Wksp=\"$WKSP\"" 1>&2
  fi
if [ $INNWKSP -eq 0 ]; then
   echo "$Default: setting Nwksp=\"$NWKSP\"" 1>&2
  fi
if [ $INHEADERS -eq 0 ]; then
   echo "$Default: setting Headers=\"$HEADERS\"" 1>&2
  fi
if [ $INCALLS -eq 0 ]; then
   echo "$Default: setting Calls=\"$CALLS\"" 1>&2
  fi
if [ $INCDATA -eq 0 ]; then
   echo "$Default: setting ConstData=\"$CDATA\"" 1>&2
  fi

if [ $INHEADERS -eq 0 -o $INCALLS -eq 0 ]; then
   echo "
$WARNING: To make the generated driver routines touch-free,
you need to set \"Headers\" and \"Calls\" in your setfile." 1>&2
else
   echo "
[1;7mINFORM[m:  You set Headers=\"$HEADERS\" and Calls=\"$CALLS\".
         You do not have to touch the driver routines
         except the inclusion files." 1>&2
fi

#-------------------------------------------
#--- Complete $MAINCPP ---------------------
#-------------------------------------------

if [ -f $MAINCPP ]; then
   mv $MAINCPP $MAINCPP.bak
   if [ $verbose -ne 0 ] ; then
      echo "
${MAINCPP}: moved to $MAINCPP.bak" 1>&2
   fi
fi

MAINHEAD > $MAINCPP
echo "
typedef  double TYPE;
typedef  $ATYPE ATYPE;
typedef  $VTYPE VTYPE;
typedef  $DTYPE DTYPE;
" >> $MAINCPP

if [ "$HEADERS" != "" ]; then
   HEADERS="`echo $HEADERS | sed -e 's/\,/\ /g'`"
   for i in $HEADERS; do
      echo "#include \"$i\"" >> $MAINCPP
      if [ ! -f $i ]; then
         echo "$WARNING: no \"$i\" exists in cwd." 1>&2
      fi
   done
fi

echo "
extern \"C\" void setups($CHAR1,${EXTERN});" >> $MAINCPP

if [ "$INFOFILE" != "" ]; then
   echo "
extern \"C\" void readdata(char*datafile,$DEXTERN);" >> $MAINCPP
fi

echo "
main(){"  >> $MAINCPP

if [ "$NARR" != "0" ]; then
   echo "   ATYPE *${ARRAY};" >> $MAINCPP
fi
if [ "$NWKSP" != "0" ]; then
   echo "   ATYPE *${WKSP};" >> $MAINCPP
fi

echo "   char  *setfile;
   int   ierr;
   int   narr,nwksp;" >> $MAINCPP

if [ "$INFOFILE" != "" ]; then
   echo "   char  infofile[MAX_LEN];
   char  datafile[MAX_LEN];
   int   ndata;" >> $MAINCPP
   for i in $ALLDATA; do
      echo "   DTYPE *${i};" >> $MAINCPP
   done
fi

for i in $MAINVAR; do
   if [ "$i" = "int" ]; then
      type="$i  "
   elif [ "$i" = "VTYPE" -o "$i" = "char" ]; then
      type="$i"
   else
      if [ "$type" = "char" ]; then
         echo "   $type  ${i}[MAX_LEN];" >> $MAINCPP
      else
         echo "   $type $i;" >> $MAINCPP
      fi
   fi
done

if [ $INLEVEL -eq 0 ]; then
   echo '   int   level;' >> $MAINCPP
fi

echo "
   level=0;
   ierr=0;
   setfile=\"$SETFILE\";" >> $MAINCPP

echo '
   /*******************************************************/' >> $MAINCPP

echo "
   setups($CHAR2,${MAINCALL});"  >> $MAINCPP


if [ "$PROGRAM" != "" ]; then
   PROGRAM="`echo $PROGRAM | sed -e 's/_/\ /g' -e 's/\,/\,\ /g' |
                             sed -e 's/\;/\;\ /g' |
                             sed -e 's/\ \ /\ /g'`"
   PROGRAM="PROGRAM $PROGRAM"
  fi
echo "
   if(level>=3) cout<<endl;
   if(level>=1) cout<<\"MAIN: $PROGRAM\"<<endl;" >> $MAINCPP

if [ "$AUTHOR" != "" ]; then
   AUTHOR="`echo $AUTHOR | sed -e 's/_/\ /g' -e 's/\,/\,\ /g' -e 's/\;/\;\ /g' |
                           sed -e 's/\ \ /\ /g'`"
   echo "   if(level>=2) cout<<\" Author: $AUTHOR\"<<endl;" >> $MAINCPP
  fi
if [ "$DATE" != "" ]; then
   DATE="`echo $DATE | sed -e 's/_/\ /g' -e 's/\,/\,\ /g' -e 's/\;/\;\ /g' |
                       sed -e 's/\ \ /\ /g'`"
   echo "   if(level>=2) cout<<\" Date:   $DATE\"<<endl;" >> $MAINCPP
  fi
if [ "$COMMENT" != "" ]; then
   for i in $COMMENT; do
   i="`echo $i | sed -e 's/_/\ /g' -e 's/\,/\,\ /g' -e 's/\;/\;\ /g' |
                 sed -e 's/\ \ /\ /g'`"
   echo "   if(level>=2) cout<<\" Comment: $i\"<<endl;" >> $MAINCPP
   done
  fi

echo "
   narr=$NARR;
   nwksp=$NWKSP;" >> $MAINCPP

if [ "$NARR" != "0" ]; then
   echo "   ${ARRAY}=new ATYPE[narr]; assert(${ARRAY}!= 0);" >> $MAINCPP
fi
if [ "$NWKSP" != "0" ]; then
   echo "   ${WKSP}=new ATYPE[nwksp]; assert(${WKSP}!= 0);" >> $MAINCPP
fi

count=0
count2=0
for par in $ALLNDATA; do
   count=`expr $count + 1`
   DATA0="`echo $par | sed -e 's/=.*//'`"
   NDATA0="`echo $par | sed -e 's/.*=//'`"
   case $NDATA0 in
     \[*\]*\[*\]) N1="`echo $NDATA0 | sed -e 's/\].*//'  | sed -e 's/\[//'`"
                  N2="`echo $NDATA0 | sed -e 's/.*\[//g' | sed -e 's/\]//'`" ;;
     *)  N1="`echo $NDATA0 | sed -e 's/\*.*//'`"
         N2="`echo $NDATA0 | sed -e 's/.*\*//'`"
         if [ "${N1}*${N2}" != "$NDATA0" ]; then
            echo "" 1>&2
            echo "ERROR: ndata gvein in ${count}-th datafile is wrong." 1>&2
            echo "You may set ndata=[n1][n2] or ndata=[n1]*[n2]." 1>&2
            echo "Forced to Quit!" 1>&2; exit 1
         fi
       ;;
   esac
   NDATA0="`echo $NDATA0 | sed -e 's/\]\[/\)\*\(/' |\
                           sed -e 's/\[/\(/g' -e 's/\]/\)/g'`"
   if [ $count -gt $NOI -a $count2 -eq 0 ]; then
      echo "

   char *DATA_FILE;" >> $MAINCPP
   else
      echo "
" >> $MAINCPP
   fi
if [ $count -le $NOI ]; then
   if [ $NOI -ge 2 ]; then
      echo "   if(idata==$count){" >> $MAINCPP
   fi
   echo "   ndata=$NDATA0;
   $DATA0=new DTYPE[ndata]; assert(${DATA0}!= 0);
   readdata(datafile,$N1,$N2,$DATA0,level,&ierr);
   if(level>=1)
      cout<<\"MAIN: ${DATA0}[$N1][$N2]=\"<<datafile
          <<\"; ($N1=\"<<$N1<<\" & $N2=\"<<$N2<<\")\"<<endl;" >> $MAINCPP
   if [ $NOI -ge 2 ]; then
      echo "   }" >> $MAINCPP
   fi
else
   count2=`expr $count2 + 1`
   ntmp=0
   for i in $CINFO; do
      ntmp=`expr $ntmp + 1`
      if [ $ntmp -eq $count2 ]; then
         DF="${i}$DATAEXT"
      fi
   done
   echo "   DATA_FILE=\"$DF\";
   ndata=$NDATA0;
   $DATA0=new DTYPE[ndata]; assert(${DATA0}!= 0);
   readdata(DATA_FILE,$N1,$N2,$DATA0,level,&ierr);
   if(level>=1)
      cout<<\"MAIN: ${DATA0}[$N1][$N2]=\"<<DATA_FILE
          <<\"; ($N1=\"<<$N1<<\" & $N2=\"<<$N2<<\")\"<<endl;" >> $MAINCPP
fi
done

echo "

   if(level>=3 && (narr==0 || nwksp==0)){" >> $MAINCPP

if [ "$INFOFILE" != "" ]; then
   echo '      cout<<" ndata="<<ndata<<endl;' >> $MAINCPP
fi

echo '      cout<<" narr="<<narr<<" "<<"nwksp="<<nwksp<<endl;
      cout<<" WARNING: You may have to edit for correct array sizes."<<endl;
      }' >> $MAINCPP

echo '
   /*******************************************************/
' >> $MAINCPP

if [ "$CALLS" != "" ]; then
   CALLS="`echo $CALLS | sed -e 's/\,/\ /g'`"
   for i in $CALLS; do
      echo "   #include \"$i\"" >> $MAINCPP
      if [ ! -f $i ]; then
         echo "$WARNING: no \"$i\" exists in cwd." 1>&2
      fi
   done
fi

echo "
   if(level>=1){
      cout<<\"MAIN:\";
      if(ierr==0) cout<<\" Successful computation!!\"<<endl;
      else        cout<<\" Something is wrong!!\"<<endl;
     }

}
" >> $MAINCPP

if [ $verbose -ne 0 ] ; then
   echo "New [1;7m$MAINCPP[m is created" 1>&2
fi

#-------------------------------------------
#---- Print $README & $CSPARS --------------
#-------------------------------------------

if [ $LEVEL -ge 3 ]; then

   DOC > $README
   echo "=================================================
" >> $README
   F77EXTERN >> $README

   grep -e include -e define -e typedef -e extern -e void \
        -e TYPE -e int -e VTYPE -e char -e setfile $MAINCPP > $CSPARS

   echo "
if(level>=3)
   \"$README\" and \"$CSPARS\" are created." 1>&2

fi

#-------------------------------------------
#--- Complete $IOSETC ---------------------
#-------------------------------------------

if [ -f $IOSETC ]; then
   mv $IOSETC $IOSETC.bak
   if [ $verbose -ne 0 ] ; then
      echo "
${IOSETC}: moved to $IOSETC.bak" 1>&2
   fi
fi
IOHEAD > $IOSETC
echo "
typedef  double TYPE;
typedef  $ATYPE ATYPE;
typedef  $VTYPE VTYPE;
typedef  $DTYPE DTYPE;
" >> $IOSETC

echo "void setups($CHAR1,${EXTERN})
{" >> $IOSETC

if [ "$IOCHAR" != "" ]; then
   for i in $IOCHAR; do
      echo "   char ${i}[MAX_LEN];" >> $IOSETC
   done
fi

echo "
   FILE *fp000;

   if ((fp000=fopen(setfile,\"r\"))==NULL){
       printf(\"Error in SETUPS: when try to open <%s>$SN\",setfile);
       *ierr=1;return;}
   fscanf(fp000,\"$FSCANF\",
          $SCANVAR);
   if(*level>=1) printf(\"SETUPS: from <%s>$SN\",setfile);
   if(*level>=3) {" >> $IOSETC

a1=
for i in $FSCANF; do
   if [ "$a1" = "" ]; then
      a1=$i
      t1="`echo $i | sed -e 's/=.*//'`"
      if [ "`echo $i | grep '%s'`" = "" ]; then
         t1="*$t1"
      fi
   else
      a2=$i
      t2="`echo $i | sed -e 's/=.*//'`"
      if [ "`echo $i | grep '%s'`" = "" ]; then
         t2="*$t2"
      fi
      echo "      printf(\" $a1 ${a2}$SN\",${t1},${t2});" >> $IOSETC
      a1=''
   fi
done
if [ "$a1" != "" ]; then
   echo "      printf(\" ${a1}$SN\",$t1);" >> $IOSETC
fi


echo '   }
   fclose(fp000);' >> $IOSETC

#-----------------------------------
count=0
for file in $INFOFILE; do
   count=`expr $count + 1`
   PARS="`cat $file | sed -e 's/\ =/=/g' -e 's/=\ /=/g' -e 's/\"//g'`"
   npar=`echo $PARS | wc -w`
   if [ $npar -eq 0 ]; then
      echo "$file does not exist or is empty." 1>&2
      echo "Forced to Quit!" 1>&2; exit 1
   fi
   SCANVAR=; FSCANF=

   for par in $PARS; do
      t1="`echo $par | sed -e 's/=.*//'`"
      if [ "$t1" = "ierr" -o "$t1" = "level" ]; then
         echo "\"$t1\" cannot be a parameter in $file" 1>&2
         echo "Forced to Quit!" 1>&2; exit 1
      fi
      t2="`echo $par | sed -e 's/.*=//'`"
      idnum=`echo $t2 | awk '{if($1~/^[-]?[.]?[0-9]/){print 1} else {print 0}}'`
      if [ $idnum -eq 1 ]; then
         t3="`echo $t2 | sed -e 's/\..*//'`"
         if [ "$t2" = "$t3" ]; then
            type=int;   field=d
         else
            type=VTYPE; field=g
         fi
      else
         type=char; field=s
      fi

      if [ "$FSCANF" = "" ]; then
         FSCANF="$t1=%$field"
      else
         FSCANF="$FSCANF $t1=%$field"
      fi
      if [ "$SCANVAR" = "" ]; then
         SCANVAR="$t1"
      else
         SCANVAR="$SCANVAR,$t1"
      fi
   done

   if [ "$VTYPE" = "double" ]; then
      FSCANF="`echo $FSCANF | sed -e 's/\=\%g/\=\%lg/g'`"
   fi

   echo "" >> $IOSETC

   if [ $count -le $NOI ]; then

      if [ $NOI -ge 2 ]; then
         echo "   if(*idata==$count){" >> $IOSETC
      fi
      echo "   strcpy(infofile,\"$file\");
   strcpy(datafile,\"${file}$DATAEXT\");
   if ((fp000=fopen(infofile,\"r\"))==NULL){
       printf(\"Error in SETUPS: when try to open <%s>$SN\",infofile);
       *ierr=1;return;}
   fscanf(fp000,\"$FSCANF\",$SCANVAR);
   if(*level>=1) printf(\"DATASETUP: from <%s>$SN\",infofile);
   if(*level>=3) {" >> $IOSETC

   else

      echo "   if ((fp000=fopen(\"$file\",\"r\"))==NULL){
       printf(\"Error in SETUPS: when try to open <%s>$SN\",\"$file\");
       *ierr=1;return;}
   fscanf(fp000,\"$FSCANF\",$SCANVAR);
   if(*level>=1) printf(\"DATASETUP: from <%s>$SN\",\"$file\");
   if(*level>=3) {" >> $IOSETC

   fi

   a1=
   for i in $FSCANF; do
      if [ "$a1" = "" ]; then
         a1=$i
         t1="`echo $i | sed -e 's/=.*//'`"
         if [ "`echo $i | grep '%s'`" = "" ]; then
            t1="*$t1"
         fi
      else
         a2=$i
         t2="`echo $i | sed -e 's/=.*//'`"
         if [ "`echo $i | grep '%s'`" = "" ]; then
            t2="*$t2"
         fi
         echo "      printf(\" $a1 ${a2}${SN}\",$t1,$t2);" >> $IOSETC
         a1=''
      fi
   done
   if [ "$a1" != "" ]; then
      echo "      printf(\" ${a1}${SN}\",$t1);" >> $IOSETC
   fi

   echo '      }
   fclose(fp000);' >> $IOSETC

   if [ $count -le $NOI ]; then
      if [ $NOI -ge 2 ]; then
         echo '   }' >> $IOSETC
      fi
   fi
done

#-----------------------------------

echo '
  return;
}
' >> $IOSETC

if [ $verbose -ne 0 ] ; then
   echo "New [1;7m$IOSETC[m is created" 1>&2
fi

#-------------------------------------------
#--- Complete $READDATA --------------------
#-------------------------------------------

FSCANDATA="%g"
if [ "$DTYPE" = "double" ]; then
   FSCANDATA="%lg"
elif [ "$DTYPE" = "int" ]; then
   FSCANDATA="%d"
fi

if [ "$INFOFILE" = "" ]; then
   if [ $verbose -ne 0 ] ; then
      LASTINFORM 1>&2
   fi
   exit 1
fi

if [ -f $READDATA ]; then
   mv $READDATA $READDATA.bak
   if [ $verbose -ne 0 ] ; then
      echo "
${READDATA}: moved to $READDATA.bak" 1>&2
   fi
fi

DATAHEAD > $READDATA
echo "
typedef  double TYPE;
typedef  $ATYPE ATYPE;
typedef  $VTYPE VTYPE;
typedef  $DTYPE DTYPE;
" >> $READDATA

echo "void readdata(char*datafile,$DANSWER)
{
   FILE *fp000;
   int i,j;
   if (level >= 1)
      printf(\"ReadDATA: from <%s>$SN\",datafile);

   if ((fp000=fopen(datafile,\"r\"))==NULL){
       printf(\"Error in ReadDATA: when try to open <%s>$SN\",datafile);
       *ierr=1;return;}

   for(i=0;i<n1;i++)
   for(j=0;j<n2;j++)
      fscanf(fp000,\"$FSCANDATA\",&${DATA}[i][j]);               
   
   if(level>=3)
   for(i=0;i<n1;i++){
   for(j=0;j<n2;j++)
         printf(\" $FSCANDATA\",${DATA}[i][j]);
      printf(\"$SN\");
    }

   if(level>=5)
   printf(\" ReadDATA: you may have to edit it.$SN\");

   fclose(fp000);
   return;
}
" >> $READDATA

if [ $verbose -ne 0 ] ; then
   echo "New [1;7m$READDATA[m is created" 1>&2
fi

#-------------------------------------------
#--- Print Message ------------------------
#-------------------------------------------

if [ $verbose -ne 0 ] ; then
   LASTINFORM 1>&2
fi

