#!/bin/bash
# Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
# HYPRE Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

# Generate code for multiprecision functions
#
# The script takes a prototype info file (generated by 'gen_proto_info.sh') and
# an output file prefix, then generates files prefix.c and prefix.h containing
# function implementations and prototypes for each line of prototype info.
#
# Usage:   <this-script> <proto-info> <prefix>
# Example: <this-script> mup.functions.ext.proto mup_functions_ext

scriptdir=`dirname $0`

PFILE=$1
OUTC="$2.c"
OUTH="$2.h"

echo "" > $OUTC
echo "" > $OUTH

# loop over lines and generate code for each function
awk -v filename="$PFILE" -v outc="$OUTC" -v outh="$OUTH" 'BEGIN {
   FS=" , "
   # Read the prototype info file
   while (getline < filename)
   {
      fret  = $1
      fdef  = $2
      tab   = "   "
      p_str = ""
      s_str = ""
      for(i=3; i<=NF; i++)
      {
         argall = sprintf("%s", $i)
         # Find the last legal C token in the argument (should not start with numbers)
         # This helps to address arguments like const double foo[3]
         laststart  = 1;
         lastlength = 0;
         while ( match(substr($i, laststart + lastlength), /[a-zA-Z_][a-zA-Z0-9_]*/) )
         {
            laststart  = laststart + lastlength + RSTART - 1
            lastlength = RLENGTH
         }
         argvar = substr($i, laststart, lastlength)
         sub(/^[[:blank:]]*/, "", argall); sub(/[[:blank:]]*$/, "", argall)
         sub(/^[[:blank:]]*/, "", argvar); sub(/[[:blank:]]*$/, "", argvar)
         p_str = sprintf("%s %s", p_str, argall)
         s_str = sprintf("%s %s", s_str, argvar)
         if(i<NF)
         {
            p_str = sprintf("%s,", p_str)
            s_str = sprintf("%s,", s_str)
         }
      }
      if (NF < 3)
      {
         # This is a special case Foo(void) function
         p_str = " void "
         s_str = " precision "
      }
      else
      {
         p_str = sprintf("%s ", p_str)
         s_str = sprintf(" precision,%s ", s_str)
      }

      arg_flt      = sprintf("%s", p_str)
      arg_dbl      = sprintf("%s", p_str)
      arg_long_dbl = sprintf("%s", p_str)
      arg_mup      = sprintf("%s", p_str)

      gsub(/(HYPRE_Real|HYPRE_Complex)/, "hypre_float", arg_flt)
      gsub(/(HYPRE_Real|HYPRE_Complex)/, "hypre_double", arg_dbl)
      gsub(/(HYPRE_Real|HYPRE_Complex)/, "hypre_long_double", arg_long_dbl)

      # First replace HYPRE_Real* and HYPRE_Complex* with void*
      gsub(/(HYPRE_Real|HYPRE_Complex)[[:blank:]]*[*]+/, "void *", arg_mup)
      gsub(/(HYPRE_Real|HYPRE_Complex)/, "hypre_long_double", arg_mup)

      print fret"\n"fdef"_flt("arg_flt");"           >> outh
      print fret"\n"fdef"_dbl("arg_dbl");"           >> outh
      print fret"\n"fdef"_long_dbl("arg_long_dbl");" >> outh
      print fret"\n"fdef"("arg_mup");\n"             >> outh

      print "/*--------------------------------------------------------------------------*/\n" >> outc
      print fret"\n"fdef"("arg_mup")"                                                          >> outc
      print "{"                                                                                >> outc
      print tab "HYPRE_Precision precision = hypre_GlobalPrecision();"                         >> outc
      print tab "return "fdef"_pre("s_str");"                                                  >> outc
      print "}\n"                                                                              >> outc
   }
   close(filename)
}'
