#!/bin/sh
     ###################################### 
     ##### Model Transformation Tools #####
     ######################################

# Bourne shell script: mtt_header
# Headings for functions
# Copyright (C) 2000 by Peter J. Gawthrop

###############################################################
## Version control history
###############################################################
## $Id$
## $Log$
## Revision 1.64  2004/08/29 01:48:46  geraint
## Added rules to create headers for sorted systems: sesx and sesy.
##
## Revision 1.63  2004/08/28 22:08:41  geraint
## Fixed zeromatrices statements: spaces instead of commas
##
## Revision 1.62  2004/07/19 22:22:25  geraint
## Fixed initialisation of ColumnVectors for -oct.
##
## Revision 1.61  2004/06/21 16:30:41  gawthrop
## Don't zero for cc code
##
## Revision 1.60  2004/06/21 16:05:58  gawthrop
## Zapped comment that causes
##
## Revision 1.59  2004/06/20 13:53:06  gawthrop
## Initialise for numpar as well
##
## Revision 1.58  2004/06/20 13:34:11  gawthrop
## Create vectors using zeros(N,1) - avoids new octave
## default to row vector - more reps now included
##
## Revision 1.57  2004/06/20 10:18:00  gawthrop
## Explicitly size vectors - avoid default row vector bug
##
## Revision 1.56  2003/04/17 20:07:33  geraint
## Added rule to create _sese.m
##
## Revision 1.55  2002/10/30 01:15:20  gawthrop
## Now gives correct-size matrices for dm rep.
##
## Revision 1.54  2002/07/11 13:00:23  geraint
## Declared more function arguments to be "const" - improves compiler optimisation.
##
## Revision 1.53  2002/06/10 23:22:16  geraint
## Fixed problem with Matlab fsolve failing because of "user function returned Inf or Nan" (fsolve.m, line 245).
##
## Revision 1.52  2002/05/27 14:52:15  geraint
## Parameters in sfun reps are now declared using sympar.h at the top of the
## sfun*.c file instead of in individual functions. This causes the optimisation
## variables (mtt_tmp*) to be declared correctly without causing conflicts in the
## scope of parameter declarations.
##
## Revision 1.51  2002/05/19 13:01:21  geraint
## Numerical solution of algebraic equations implemented for S-function target.
##
## Equation solving requires the Matlab Optimization Toolbox to be installed.
##
## Code has been changed from C++ to C to allow mex files to be built with LCC,
## the compiler bundled with Matlab.
##
## Parameters are now obtained from numpar.c instead of a dialogue box.
##
## `mtt <sys> sfun zip` creates all necessary files for building the model mex files.
##
## Revision 1.50  2002/05/15 14:22:25  geraint
## Code for Simulink S-function target written direct to sfun.cc instead of
## calling .mexglx files. This eliminates the sfun dependency on Octave
## ColumnVectors. sys_sfun.cc should build directly on a MS Windows machine
## (can't test this yet).
##
## added sfun.zip target to create source code to export.
##
## Revision 1.49  2002/05/11 01:14:17  geraint
## Fix for [ 553218 ] simpar.oct and simpar.m different.
## Translation added between ColumnVector in base .cc and Octave_map in .oct.
##
## Revision 1.48  2002/05/08 14:51:03  geraint
## Moved matlab/octave data type conversion functions to a separate file.
##
## Revision 1.47  2002/05/07 23:50:34  geraint
## Preliminary support for Matlab dynamically linked shared objects:
## invoke with: mtt -cc sys rep mexglx
## ode2odes support is not yet included.
##
## Revision 1.46  2002/05/07 13:48:43  geraint
## Improved clarity of code generated for -cc and -oct (except ode2odes).
## Octave DEFUN_DLDs now call (rather than replace) their .cc equivalents.
##
## Revision 1.45  2002/05/02 09:30:22  gawthrop
## _ssim.m now returns t as 4th arg
##
## Revision 1.44  2002/05/01 17:30:56  geraint
## Improved pre-processor directives to better accommodate future alternatives (matlab)
## if necessary.
##
## Revision 1.43  2002/04/30 23:27:00  geraint
## Replaced octave_map with columnvector in simpar.cc. Not quite as descriptive but
## standardises the interfaces somewhat and reduces the dependency on liboctinterp
## (and thus libreadline, libkpathsea, libncurses, etc).
##
## Revision 1.42  2002/04/28 18:41:27  geraint
## Fixed [ 549658 ] awk should be gawk.
## Replaced calls to awk with call to gawk.
##
## Revision 1.41  2002/04/23 17:46:05  gawthrop
## _sim.m now returns time as third argument
##
## Revision 1.40  2002/04/17 16:23:59  geraint
## Partial fix for [ 545113 ] zeros missing in c++.
## Fixes -oct by removing duplicate initialisation (-c is still outstanding).
##
## Revision 1.39  2002/04/15 10:54:31  geraint
## Statically declare outputs and initialise to zero.
## This is necessary to prevent spurious values from being output when no assignments are made (i.e. when "y(i) := 0 for all u"  (Reduce:see NERO)).
##
## Revision 1.38  2001/07/23 23:43:15  gawthrop
## header only version does not need to compute sizes from _def.r
##
## Revision 1.37  2001/07/13 04:54:04  geraint
## Branch merge: numerical-algebraic-solution back to main.
##
## Revision 1.36  2001/07/12 04:00:51  gawthrop
## Now zeros y correctly - ie Ny NOT Nx elements
##
## Revision 1.35  2001/06/13 10:39:51  gawthrop
## Zeros output matices in csex and cseo just in case some elements are
## actually zero and not set in code. Works for m and oct.
##
## Revision 1.34  2001/05/26 18:36:43  gawthrop
## Further modifications. Now works on rcPPP
##  -- next jobs:
##     add identification to ppp_nlin_sim
##     create real-time ppp_nlin_run
##
## Revision 1.33  2001/05/26 15:46:38  gawthrop
## Updated to account for new nonlinear ppp
##
## Revision 1.32  2001/05/24 07:42:12  gawthrop
## Included and updated the missing tf_r2m
##
## Revision 1.31.2.2  2001/07/02 00:34:56  geraint
## gcc-3.0 compatibility.
##
## Revision 1.31.2.1  2001/05/04 04:07:24  geraint
## Numerical solution of algebraic equations.
## sys_ae.cc written for unsolved inputs.
## Solution of equations using hybrd from MINPACK (as used by Octave fsolve).
##
## Revision 1.31  2001/04/03 14:49:42  gawthrop
## Revised to incorporate new ssim (sensitivity simulation)
## representation (m only just now).
##
## Revision 1.30  2001/03/30 15:13:58  gawthrop
## Rationalised simulation modes to each return mtt_data
##
## Revision 1.29  2001/03/27 13:10:23  geraint
## Improved determination of Octave version.
##
## Revision 1.28  2001/02/17 03:48:17  geraint
## Use assignment LHS to gather tmp variable names.
## Prevents collection of long expressions, eg: tmp34*(tmp75
##
## Revision 1.27  2001/02/14 06:06:34  geraint
## Removed octave_value_list wrappers from standalone.exe - speed improvements
##
## Revision 1.26  2001/02/05 08:50:58  geraint
## Octave 2.1.x compatability.
##
## Revision 1.28  2001/01/17 21:16:15  geraint
## uncomment parameter assignments in .m reps
##
## Revision 1.27  2001/01/14 23:51:26  geraint
## declare parameters as variables instead of constants
##
## Revision 1.26  2001/01/07 21:22:47  geraint
## Compatibility with Octave 2.1.x
## vector_value ---> column_vector_value
##
## Revision 1.25  2000/12/05 12:05:26  peterg
## Changed to () form
##
## Revision 1.24  2000/12/05 10:04:52  peterg
## Fixed dummy variable bug
##
## Revision 1.23  2000/12/05 09:47:50  peterg
## Include crs as c files
##
## Revision 1.22  2000/12/04 12:19:12  peterg
## Changed $() to `` and $() to expr for sh compatibility -- geraint
##
## Revision 1.21  2000/12/04 08:52:40  peterg
## Zapped () in functions for sh compatibility
##
## Revision 1.20  2000/12/04 08:19:27  peterg
## Added switch declarations - in logic.cc
##
## Revision 1.19  2000/12/03 16:11:43  peterg
## Corrected bug in logic declatations
##
## Revision 1.18  2000/12/03 16:06:22  peterg
## Fixed bug in generating dummies
## Added logic declarations
##
## Revision 1.17  2000/12/01 20:55:01  peterg
## Added Geraint's fix for zeroing matrices
##
## Revision 1.16  2000/12/01 17:56:30  peterg
## Removed spurious  echo '## Set matrices to zero' - thanks Geraint
##
## Revision 1.15  2000/11/29 21:06:16  peterg
## Removed Npar creation - not needed??
##
## Revision 1.14  2000/11/27 11:51:43  peterg
## Added zero matrices in matlab code
##
## Revision 1.13  2000/11/09 17:19:52  peterg
## Geraint's pow() mods
##
## Revision 1.12  2000/11/09 16:09:46  peterg
## Declare dummy variables (mtt_s1 etc)
##
## Revision 1.11  2000/11/09 15:29:35  peterg
## lower-case declarations
##
## Revision 1.10  2000/11/07 17:20:51  peterg
## useful-functions.hh now included locally
##
## Revision 1.9  2000/11/07 16:56:24  peterg
## Version from Geraint
##
## Revision 1.2  2000/11/03 00:55:42  geraint
## typo: missed out 'd' in mttedx
## todo: need to accommodate mttsimpar
##
## Revision 1.1  2000/11/02 04:28:39  geraint
## Initial revision
##
## Revision 1.8  2000/10/17 16:35:03  peterg
## No parameter,state or input conversion in txt files
##
## Revision 1.7  2000/10/17 09:53:20  peterg
## Fixed logic rep
##
## Revision 1.6  2000/10/17 08:37:23  peterg
## Included logic rep
##
## Revision 1.5  2000/10/14 09:12:14  peterg
## No dies arguments and output itself
##
## Revision 1.4  2000/10/14 06:49:31  peterg
## Make parameter listing representation dependent
##
## Revision 1.3  2000/10/11 08:59:15  peterg
## Added csex rep
##
## Revision 1.2  2000/10/11 08:01:42  peterg
## Added noglobal fudge
##
## Revision 1.1  2000/10/10 21:02:27  peterg
## Initial revision
##
###############################################################

# Arguments
system=$1
rep=$2
language=$3
fun_name=${1}_${2}

other=$4 # Anything else eg stdin

insertor=\<\<			# help emacs sh-mode with C++ lines


if [ -z "$system" ]; then
  echo 'Usage: mtt_header sys rep lang [stdin]'
  exit
fi


# get octave version
octave_development=`octave --version | gawk '{print $4}' | gawk -F\. '{print $2}'`
case `$MATRIX --version | gawk -F\. '{print $2}'` in
    0) # stable
	vector_value=vector_value
	;;
    1) # development
	vector_value=column_vector_value
	;;
    *)
	vector_value=column_vector_value
	;;
esac


# Representation-specific stuff

eqnargs='mttx,mttu,mttt,mttpar'
inputeqnargs='mttx,mtty,mttt,mttpar'
case $rep in
    ae)
	states=yes;
	inputs=yes;
	parameters=yes;
	output=mttyz;
	args=$eqnargs;
	;;
    cse)
	states=yes;
        inputs=yes;
	parameters=yes;
        output='mttdx,mtte'
        args=$eqnargs
	zeromatrices='dx e'
	;;
    csex)
	states=yes;
        inputs=yes;
	parameters=yes;
        output=mttedx
        args=$eqnargs
        zeromatrices='edx';
	;;
    cseo)
	states=yes;
        inputs=yes;
	parameters=yes;
        output=mtty
        args=$eqnargs
        zeromatrices='y';
	;;
    dm)
	states=no;
	inputs=no;
	parameters=yes;
        output='mtta,mttb,mttc,mttd,mtte'
        args=mttpar
        zeromatrices='a b c d e';
	;;
   input)
	inputs=no;
        output=mttu
        args=$inputeqnargs
        if [ "$other" = "stdin" ]; then
	  states=no;
	  parameters=no;
          declareinputs=no;
        else
	  states=yes;
	  parameters=yes;
          declareinputs=yes
	  declarestates=yes
	  zeromatrices='u'
        fi
	;;
    logic)
	states=no;
	inputs=no;
	parameters=yes;
        output=mttopen
        args=$eqnargs
        declareinputs=yes
        declarestates=yes
	declareswitches=yes
        zeromatrices='open';
	;;
    numpar)
	states=no;
	inputs=no;
	parameters=no;
        output='mttpar'
	zeromatrices='par'
	;;
    ode)
	states=yes;
        inputs=yes;
	parameters=yes;
        output='mttdx'
        args=$eqnargs
	zeromatrices='dx'
	;;
    odeo)
	states=yes;
        inputs=yes;
	parameters=yes;
        output='mtty'
        args=$eqnargs
	zeromatrices='y'
	;;
    ode2odes)
	states=no;
        inputs=no;
	parameters=no;
        output='mtt_data'
        args='x0,par,simpar'
	;;
    simpar)
	states=no;
	inputs=no;
	parameters=no;
	output='mttsimpar'
	oct_rep_include="#include <mtt_simpar.hh>"
	oct_return_type="mtt_simpar"
	;;
    sae)
	states=yes;
	inputs=yes;
	parameters=yes;
	output=mttyz;
	args=$eqnargs;
	;;
    sese)
	states=yes;
	inputs=yes;
	parameters=yes;
	output="mttdx,mtty";
	args=$eqnargs;
	zeromatrices="dx y";
	;;
    sesx)
	states=yes;
        inputs=yes;
	parameters=yes;
        output='mttdx'
        args=$eqnargs
	zeromatrices='dx'
	;;
    sesy)
	states=yes;
        inputs=yes;
	parameters=yes;
        output='mtty'
        args=$eqnargs
	zeromatrices='y'
	;;
    sm)
	states=no;
	inputs=no;
	parameters=yes;
        output='mtta,mttb,mttc,mttd'
        args=mttpar;
        zeromatrices='a b c d';
	;;
     smxa)
	states=no;
        inputs=no;
	parameters=yes;
        output='mtta'
        args=$eqnargs
        zeromatrices='a';
	;;
    smxax)
	states=no;
        inputs=no;
	parameters=yes;
        output='mttax'
        args=$eqnargs
        zeromatrices='ax';
	;;
    state)
	states=no;
	inputs=no;
	parameters=yes;
        output=mttx
        args=mttpar
        declarestates=yes
	zeromatrices='x'
	;;
    sim)
	states=no;
        inputs=no;
	parameters=no;
        output='y,x,t'
        args='x0,par,simpar,u'
	;;
    ssim)
	states=no;
        inputs=no;
	parameters=no;
        output='y,y_par,x,t'
        args='x0,par,simpar,u,index'
	;;
    tf)
	states=no;
	inputs=no;
	parameters=yes;
        output='mttnum,mttden'
        args=mttpar;
	;;    
    type)
	states=no;
	inputs=no;
	parameters=no;
	header_only=yes;
	;;

     *)
	echo Representation $rep not supported - sorry; exit 1
esac

## Sort out parentheses
if [ -n "$args" ]; then
    Args='('$args')'
fi
if [ -n "$output" ]; then
    Output="[$output] = "
fi


# Lanuage specific stuff
case $language in
    m)
	Lc='##';
	Rc='';
	Lb='(';
	Rb=')';
	function="function"
	declaration="$Output$1_$rep$Args;"
        if [ "$other" != "stdin" ]; then
	  noglobals=true; # Fudge to make mtt_m2p work
        fi     
        start='## BEGIN Code'
        finish='## END Code'
        var_declaration=
        declarestates=no
        declareinputs=no
	declareswitches=no
	;;
    sh)
	modeline='## -*-shell-script-*- Put Emacs into shell-script-mode ##';
	Lc='##';
	Rc='';
	Lb='(';
	Rb=')';
	function=""
	declaration=""
        start=''
        parameters=no
	states=no
	inputs=no
        declarestates=no
        declareinputs=no
	declareswitches=no
	;;
    txt)
	modeline='## -*-octave-*- Put Emacs into octave-mode ##';
	Lc='##';
	Rc='';
	Lb='(';
	Rb=')';
	function=""
	declaration=""
        start=''
        parameters=no
	states=no
	inputs=no
        declarestates=no
        declareinputs=no
	declareswitches=no
	;;
    oct)
	modeline="// -*-c++-*- Put Emacs into c++-mode";
	Lc='//';
	Lb='(';
	Rb=')';
	oct_header=yes;
        constant_declaration="const double "
        var_declaration="double "
	minusone="-1"
	map="_map"
        declaredummies=yes
	;;
    c)
	modeline="/* -*-c-*- Put Emacs into c-mode */";
	Lc='/*'
	Rc='*/'
	Lb='['
	Rb=']'
	constant_declaration="const double "
	var_declaration="double "
	minusone="-1"
	;;
    *)
	echo Language $language not supported - sorry; exit 1
esac

if [ "$rep" = "simpar" ]; then
   output=${output}${map}    # Output is simpar_map in this case
fi

get_sizes()
    {
    Nx=`mtt_getsize $system x` # States
    Nz=`mtt_getsize $system z` # Non-states
    Nxx=`mtt_getsize $system xx` # States x States
    Nu=`mtt_getsize $system u` # Inputs 
    Ny=`mtt_getsize $system y` # Outputs 
    Nyz=`mtt_getsize $system yz` # Zero outputs

    case ${rep} in
	dm)
	let Nx=Nx+2*Nz+Nyz # Matrices not usual size
	;;
	*)
	
    esac
    Npar=`wc -l $system\_sympar.txt | gawk '{print $1}'`
    }

zero_matrices()
{
## Set matrices to zero
echo
for name in $zeromatrices; do
    case $name in
	a)
	    N=$Nx; M=$Nx
	    ;;
	b)
	    N=$Nx; M=$Nu
	    ;;
	c)
	    N=$Ny; M=$Nx
	    ;;
	d)
	    N=$Ny; M=$Nu
	    ;;
	e)
	    N=$Nx; M=$Nx
	    ;;
	x)
	    N=$Nx; M=0
	    ;;
	dx)
	    N=$Nx; M=0
	    ;;
	edx)
	    N=$Nx; M=0
	    ;;
	y)
	    N=$Ny; M=0
	    ;;
	u)
	    N=$Nu; M=0
	    ;;
	open)
	    N=$Nx; M=0
	    ;;
	ax)
	    N=$Nx; M=0
	    ;;
	par)
	    N=$Npar; M=0
	    ;;
	*)
	    
    esac

    case ${language} in
	m)
	  if [ "$M" = "0" ]; then
	      M=1;
	  fi
          echo "   mtt$name = zeros($N,$M);"	
	;;
	oct)
	    if [ "$M" = "0" ]; then
		echo "   mtt$name = zeros($N);"
	    else
		echo "   mtt$name = zeros($N,$M);"
	    fi
	    ;;
        *)
    esac
done
}

declare_dummies()
{
# Get the dummies
dummies="mtt_tmp"
rm -f mtt_dummies
for dummy in $dummies; do
    grep "${dummy}[0-9]*[ \t\n]*=" < ${fun_name}.m |\
    gawk '{ 
          if (match($1,dummy)==1)
             print $1
         }' dummy=$dummy >> mtt_dummies
done

dummy_list=`sort -u mtt_dummies`

# Comments
cat <<EOF

$Lc  Declarations of dummies $Rc
EOF

for dummy in $dummy_list; do
    echo '  ' $var_declaration $dummy';'
done
} # declare_dummies

declare_switches ()
{
cat <<EOF

$Lc  Declarations of switches $Rc
EOF
 strip_comments <${system}_switch.txt |\
 gawk '{printf("  double %s_logic = 0;\n", tolower($1))}' 
} # declare_switches

declare_vars()
{
# Grab the names
names=`gawk '{if ($1==var_type) print tolower($4)}' var_type=$1 ${system}_struc.txt`

# Comments
cat <<EOF

$Lc  Declarations for $1 names $Rc
EOF
# Declarations
for name in $names; do
    echo '  '$var_declaration $name';'
done
}


array2constant()
{
# Parameters
if [ "$parameters" = "yes" ]; then
cat <<EOF

$Lc Parameters $Rc
EOF
sympar2par_txt2m ${system} ""  "$var_declaration" "$minusone" "$Lb" "$Rb"
fi

# States
if [ "$states" = "yes" ]; then
cat <<EOF

$Lc States $Rc
EOF
N=`n2m 1 $Nx`
for i in $N; do
    echo $constant_declaration 'mttx'$i' = mttx'$Lb$i$minusone$Rb ';'
done
fi

if [ "$declarestates" = "yes" ]; then
  declare_vars state
fi

# Inputs
if [ "$inputs" = "yes" ]; then
cat <<EOF

$Lc Inputs $Rc
EOF

N=`n2m 1 $Nu`
for i in $N; do
  echo $constant_declaration 'mttu'$i' = mttu'$Lb$i$minusone$Rb';'
done
cat <<EOF

$Lc Unknown Inputs $Rc
EOF

Ni=`n2m 1 $Nyz`
for i in $Ni; do
  echo $constant_declaration 'mttui'$i' = mttu'$Lb$Nu+$i$minusone$Rb';'
done
fi

if [ "$declareinputs" = "yes" ]; then
  declare_vars input
fi

if [ "$declaredummies" = "yes" ]; then
  declare_dummies
fi

if [ "$declareswitches" = "yes" ]; then
  declare_switches
fi


zero_matrices;

}

# Argument specific stuff
get_arg_specific_stuff ()
{
    arg_name=${1:-""}
    case ${arg_name} in
	mtta | mtte)
	    arg_type="Matrix"
	    arg_init="(MTTNX,MTTNX,0.0)"
	    ;;
	mttb)
	    arg_type="Matrix"
	    arg_init="(MTTNX,MTTNU,0.0)"
	    ;;
	mttc)
	    arg_type="Matrix"
	    arg_init="(MTTNY,MTTNX,0.0)"
	    ;;
	mttd)
	    arg_type="Matrix"
	    arg_init="(MTTNY,MTTNU,0.0)"
	    ;;
	mttax | mttdx | mttedx | mttx | mttopen)
	    arg_type="ColumnVector"
	    arg_init="(MTTNX,0.0)"
	    ;;
	mttpar)
	    arg_type="ColumnVector"
	    arg_init="(MTTNPAR,0.0)"
	    ;;
	mttsimpar_map)
	    arg_type="ColumnVector"
	    arg_init="(8,0.0)";
	    ;;
	mttu)
	    arg_type="ColumnVector"
	    arg_init="(MTTNU,0.0)"
	    ;;
	mttyz)
	    arg_type="ColumnVector"
	    arg_init="(MTTNYZ,0.0)"
	    ;;
	mtty)
	    arg_type="ColumnVector"
	    arg_init="(MTTNY,0.0)"
	    ;;
	mttt)
	    arg_type="double"
	    arg_init=""
	    ;;
	nil)
	    arg_type="void *"
	    arg_init="(0x0)"
	    ;;
	*)
	    echo "Argument ${arg} not supported - sorry"; exit 1
    esac
}


get_field ()
{ # parse comma separated string
    s=${1:-""}					# comma separated string
    i=${2:-0}					# field number in string

    if [ 0 -eq ${i} ]; then			# return number of fields
	echo ${s} |\
	gawk -F\, '{ print NF }'
    else					# return ith field
	echo ${s} |\
	gawk -F\, -v i=${i} '{ print $i }'
    fi
}


get_extra_fields ()
{ # return list of words in s2 and not in s1
    s1=${1:-""}					# comma separated list
    s2=${2:-""}					# comma separated list

    c1=`get_field ${s1} 0`			# count words in s1
    c2=`get_field ${s2} 0`			# count words in s2
	
    ans=""
	
    i2=0					# s2 word index
    while [ ${i2} -lt ${c2} ]; do
        flag=0					# appearance of word in s1 and s2?
	i2=`expr ${i2} + 1`
	w2=`get_field ${s2} ${i2}`		# i2 th word in s2
	i1=0					# s1 word index
	while [ ${i1} -lt ${c1} ]; do
	    i1=`expr ${i1} + 1`
	    w1=`get_field ${s1} ${i1}`		# i1 th word in s1
	    if [ ${w2} = ${w1} ]; then
		flag=1				# w2 occurs in s1
	    fi
        done
	if [ ${flag} -eq 0 ]; then		# w2 is not in s1?
	    if [ -z ${ans:-""} ]; then		#  string is empty?
		ans=${w2}			#   assign w2
	    else
		ans=${ans},${w2}		#   append w2
	    fi
        fi
    done
    echo ${ans}
}


write_cc_header ()
{
    get_arg_specific_stuff ${output}
    cat <<EOF

#include <octave/oct.h>
#include "useful-functions.hh"
#include "${system}_cr.h"
#include "${system}_def.h"
#include "${system}_sympar.h"

// Code generation directives
#define STANDALONE 0
#define OCTAVEDLD  1
#define MATLABMEX  2
#ifndef CODEGENTARGET
#define CODEGENTARGET STANDALONE
#endif // CODEGENTARGET

${arg_type} ${system}_${rep} (
EOF
    if [ -z ${args:-""} ]; then
	printf "\tvoid"
    else
	c=`get_field ${args:-""} 0`
	i=0
	while [ ${i} -lt ${c} ]; do
	    i=`expr ${i} + 1`
	    if [ ${i} -lt ${c} ]; then
		comma=","
	    else
		comma=""
	    fi
	    w=`get_field ${args} ${i}`
	    get_arg_specific_stuff ${w}
	    printf "\tconst ${arg_type}\t&${w}${comma}\n"
	done
    fi
    get_arg_specific_stuff ${output}
    cat <<EOF
)
{
  static ${arg_type} ${output} ${arg_init};

EOF
}

write_cc_footer ()
{
    cat <<EOF
// BEGIN Code
// END   Code

  return ${output};
}

EOF
}


map_oct_inputs ()
{
    s=${1:-""}					# comma separated input list
    if [ -z ${s:-""} ];then return; fi
    c=`get_field ${s} 0`			# count of inputs
    i=0
    printf "  if (${c} != args.length ()) usage (\"${fun_name} expected ${c} argument(s): ${s}\");\n\n"
    while [ ${i} -lt ${c} ]; do
	j=${i}
	i=`expr ${i} + 1`
	w=`get_field ${s} ${i}`		# argument name
	get_arg_specific_stuff ${w}
	case ${arg_type} in
	    "double")
		printf "  const ${arg_type}\t${w}\t= args(${j}).double_value ();\n"
		;;
	    ColumnVector | Matrix | *)
		printf "  const ${arg_type}\t${w}\t= args(${j}).%s ();\n" ${vector_value}
		;;
	esac
    done
}	

map_mex_cc_inputs ()
{
    s=${1:-""}					# comma separated input list
    if [ -z ${s:-""} ];then return; fi
    c=`get_field ${s} 0`			# count of inputs
    i=0
    cat <<EOF
    if (${c} != nrhs)
     {
       std::cerr $insertor "${fun_name} expected " $insertor ${c} $insertor " argument(s): ${s}" $insertor std::endl;
       return;
     }
EOF
    while [ ${i} -lt ${c} ]; do
	j=${i}
	i=`expr ${i} + 1`
        w=`get_field ${s} ${i}`		# argument name
	get_arg_specific_stuff ${w}
	case ${arg_type} in
	    "const double")
		printf "  ${arg_type}\t${w}\t= mtt_double (prhs [${j}]);\n"
		;;
	    ColumnVector | Matrix | *)
		printf "  ${arg_type}\t${w}\t= mtt_${arg_type} (prhs [${j}]);\n"
		;;
	esac
    done
}	
    

write_oct()
{
    func=${1:-"<insert function name>"}
    args=${2:-""}
    cat <<EOF
#if (CODEGENTARGET == OCTAVEDLD)
$oct_rep_include

DEFUN_DLD (${system}_${rep}, args, ,
"Usage: [$output] = ${system}_${rep}($args)\nOctave ${rep} representation of system ${system}\nGenerated by MTT on `date`")
{
  static octave_value_list retval;

EOF
    map_oct_inputs ${args}
    cat <<EOF

  retval (0) = octave_value ($oct_return_type (${func} (${args})));
  return retval;
}
#endif // (CODEGENTARGET == OCTAVEDLD)

EOF
}

write_mex_cc ()
{
    func=${1:-"<insert function name>"}
    args=${2:-""}
    cat <<EOF
#if (CODEGENTARGET == MATLABMEX)
#include <mtt_matlab_octave.hh>

extern "C"
{
  void mexFunction (int nlhs, mxArray *plhs[],
		    int nrhs, const mxArray *prhs[])
  {
EOF
  map_mex_cc_inputs ${args}
cat <<EOF
  plhs[0] = mtt_mxArray (${func} (${args}));
  }
}
#endif

EOF
}

# Header information
cat<<EOF
$modeline
$function $declaration
$Lc $declaration
$Lc System $system, representation $rep, language $language; $Rc
$Lc File $1_$rep.$language; $Rc
$Lc Generated by MTT on `date`; $Rc
EOF

if [ -n "${header_only}" ]; then
    exit
else
    get_sizes;
fi

if [ ${language} = "oct" ];then
# standalone
    write_cc_header
    array2constant
    write_cc_footer
# oct and mex code
    write_oct ${system}_${rep} ${args}
    write_mex_cc ${system}_${rep} ${args}
elif [ $language = "c" ]; then
    array2constant
    cat <<EOF
/* BEGIN Code */
/* END Code */
EOF
else

if [ -n "$noglobals" ]; then
cat<<EOF

## Horrible fudge to make mtt_m2p work
global ...
mtt_no_globals ;
EOF
fi

## Arrays 
array2constant

# Mark start of code
echo
echo $start

fi
