#!/bin/bash
#

if [[ $3 == '' ]]; then
  modname=$(basename "$2" .f90)
else
  modname=$3
fi
modheader=../../$modname'_'$1's_c.h'
if [[ $1 == par ]]; then
  ptype=void
  headerdir=common
  modinit=$modheader
  modecs=../../$modname'_par_decs_c.h'
  rm $modecs
else
  ptype=int
  headerdir=diagnostics
  modinit=../../$modname'_diags_init_c.h'
  modecs=/dev/null
  rm -f $modinit
fi
#
# writes declaration of push$1s2c into $modfuncs
#
modfuncs=$headerdir/PC_module_$1funcs.h
rm -f tmp
if [ -f $modfuncs ]; then
  sed -e'/'$modname'/ d' < $modfuncs > tmp
  mv -f tmp $modfuncs
else
  echo '// automatically generated; do not edit!' > $modfuncs
fi
#
# extracts body of push$1s2c from module source > tmp
#
sed -n '
  /^ *subroutine  *push'$1's2c/,/^ *end *subroutine  *push'$1's2c/ {
  /dimension *( *: *)/ d
  /subroutine/ d
  /call  *keep_compiler/ d
  /use / d
  /set_type *(/ d
  p
  }
' < $2 > tmp
#
# writes declarations of n_$1s_<modname>, p_$1_<modname> and call of push$1s2c into $modname_$1s_c.h
#
rm -f $modheader tmp1
sed -n '
  /parameter/ {
     h
     s/^.*parameter *:: *n_'$1's\( *= *[1-9][0-9]*\) *$/const int n_'$1's_'$modname'\1;\n EXTERN '$ptype' *p_'$1'_'$modname'[n_'$1's_'$modname'];\n extern "C" void *'$MODULE_PREFIX$modname$MODULE_INFIX'push'$1's2c'$MODULE_SUFFIX'('$ptype' *(\&p_'$1')[n_'$1's_'$modname']);/
     t store
     b cont
     : store
     p
     : cont
     g
     s/^.*parameter *:: *n_'$1's\( *= *[1-9][0-9]*\) *$/'$MODULE_PREFIX$modname$MODULE_INFIX'push'$1's2c'$MODULE_SUFFIX'(p_'$1'_'$modname');/ w '$modinit'
  }
' < tmp >> $modfuncs
#
if [[ $1 == 'par' ]]; then
  sed -n '
          /copy_addr_c/ {
            s/call  *copy_addr_c(\([a-zA-Z0-9_]*\) *, *p_'$1'(\([0-9]*\))) *$/CUDA_ERRCHK( cudaMemcpyToSymbol(d_\U\1\L, p_'$1'_'$modname'[\2-1], sizeof(real)) );  \/\/ \1 real/w tmp1
            t cont
            s/call  *copy_addr_c(\([a-zA-Z0-9_]*\) *, *p_'$1'(\([0-9]*\))) *! *\([a-zA-Z][a-zA-Z]*\) *$/CUDA_ERRCHK( cudaMemcpyToSymbol(d_\U\1\L, p_'$1'_'$modname'[\2-1], sizeof(\3)) );  \/\/ \1 \3/w tmp1
            t cont
            s/call  *copy_addr_c(\([a-zA-Z0-9_]*\) *, *p_'$1'(\([0-9]*\))) *! *( *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) *) *$/CUDA_ERRCHK( cudaMemcpyToSymbol(d_\U\1\L, p_'$1'_'$modname'[\2-1], \3*sizeof(real)) );  \/\/ \1 real(\3)/w tmp1
            t cont
            s/call  *copy_addr_c(\([a-zA-Z0-9_]*\) *, *p_'$1'(\([0-9]*\))) *! *\([a-zA-Z]*\) *( *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) *) *$/CUDA_ERRCHK( cudaMemcpyToSymbol(d_\U\1\L, p_'$1'_'$modname'[\2-1], \4*sizeof(\3)) );  \/\/ \1 \3(\4)/w tmp1
            : cont
            p
          }
  '< tmp >> $modheader
else
  sed -n '
          /copy_addr_c/ {
             h
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]\)\([mr][am][sx]\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2>0) {\n  diag=reduce_cuda_PC(\U\2_VEC\L, h_grid.\U\1\1X\L);\n  save_name(diag,idiag_\1\2);\n}/ 
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]\)\(min\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2>0) {\n  diag=-reduce_cuda_PC(\U\2_VEC\L, h_grid.\U\1\1X\L);\n  save_name(diag,idiag_\1\2);\n}/ 
             t store
             b cont
             : store
             p
             : cont
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]\)\([xyz]\)\([mr][iam][nsx]\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2\3>0) {\n  diag=reduce_cuda_PC(\U\3_SCAL\L, h_grid.\U\1\1\2\L);\n  save_name(diag,idiag_\1\2\3);\n}/ 
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]\)\([xyz]\)\(min\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2\3>0) {\n  diag=-reduce_cuda_PC(\U\3_SCAL\L, h_grid.\U\1\1\2\L);\n  save_name(diag,diag_\1\2\3);\n}/ 
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]*\)\([mr][am][sx]\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2>0) {\n  diag=reduce_cuda_PC(\U\2_SCAL\L, h_grid.\U\1\L);\n  save_name(diag,idiag_\1\2);\n}/ 
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]*\)\(min\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2>0) {\n  diag=-reduce_cuda_PC(\U\2_SCAL\L, h_grid.\U\1\L);\n  save_name(diag,idiag_\1\2);\n}/ 
             s/call  *copy_addr_c *( *idiag_\([a-zA-Z0-9_]*\)\(m\) *, *p_'$1' *( *\([0-9]*\) *) *) *$/if (idiag_\1\2>0) {\n  diag=reduce_cuda_PC(\U SUM_SCAL\L, h_grid.\U\1\L);\n  save_name(diag,idiag_\1\2);\n}/ 
             t store1
             b cont1
             : store1
             p
             : cont1
             g
             s/( *idiag_\([a-zA-Z0-9_]*\) *, *p_'$1' *( *\([0-9]*\)).*$/p_'$1'_'$modname'[\2-1] \/\/ idiag_\1 int/ w tmp1
         }
  ' < tmp >> $modheader
fi
rm -f tmp
#
# writes macro definition of individual p_'$1' into $modfuncs
#
if [ -f tmp1 ]; then
  sed -n '
         /p_/ {
          s/^.*\(p_'$1'_'$modname' *\[ *[1-9][0-9]*-1 *\]\).*\/\/ *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) *\([a-zA-Z][a-zA-Z]*\) *$/#define \2 (*((\3 *) \1)) \/\/ \3 from '$modname'/
          t cont
          b dimen
          : cont
          p
          s/^#define  *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) .*\/\/ *\([a-zA-Z][a-zA-Z]*\) .*$/DCONST_EXTERN __constant__ \2 d_\U\1;/
          H
          b end
          : dimen
          s/^.*\(p_'$1'_'$modname' *\[ *[1-9][0-9]*-1 *\]\).*\/\/ *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) *\([a-zA-Z0-9_][a-zA-Z0-9_]*\)\(([a-zA-Z0-9_][a-zA-Z0-9_]*)\) *$/#define \2 ((\3 *)\1) \/\/ \3\4 from '$modname'/
          t cont1
          b end
          : cont1
          p
          s/^#define  *\([a-zA-Z0-9_][a-zA-Z0-9_]*\) .*\/\/ *\([a-zA-Z][a-zA-Z]*\)(\([a-zA-Z0-9_][a-zA-Z0-9_]*\)).*$/DCONST_EXTERN __constant__ \2 d_\U\1[\L\3];/
          H
          : end
         }
         $ {
            g
            w '$modecs'
           }
  ' < tmp1 >> $modfuncs
  rm -f tmp1
fi
#
# writes #include "$modname_$1s_c.h" into $headerdir/PC_module$1s.h
#
echo '#include "'$modheader'"' >> $headerdir/PC_module$1s.h
#
# writes #include "$modname_par_decs_c.h" into $headerdir/PC_modulepardecs.h
#
if [[ $1 == 'par' ]]; then
  echo '#include "'$modecs'"' >> $headerdir/PC_modulepardecs.h
fi

