#! /bin/sh
#-------------------------------------------------------------------------
#
# Gen_fmgrtab.sh
#    shell script to generate fmgroids.h and fmgrtab.c from pg_proc.h
#
# NOTE: if you change this, you need to fix Gen_fmgrtab.pl too!
#
# Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
#    $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.41 2009/01/01 17:23:48 momjian Exp $
#
#-------------------------------------------------------------------------

CMDNAME=`basename $0`

if [ x"$AWK" = x"" ]; then
	AWK=awk
fi

cleanup(){
    [ x"$noclean" != x"t" ] && rm -f "$SORTEDFILE" "$$-$OIDSFILE" "$$-$TABLEFILE"
}

noclean=

#
# Process command line switches.
#
while [ $# -gt 0 ]
do
    case $1 in
        --noclean)
            noclean=t
            ;;
        --help)
            echo "$CMDNAME generates fmgroids.h and fmgrtab.c from pg_proc.h."
            echo
            echo "Usage:"
            echo "  $CMDNAME inputfile"
            echo
            echo "The environment variable AWK determines which Awk program"
            echo "to use. The default is \`awk'."
            echo
            echo "Report bugs to <pgsql-bugs@postgresql.org>."
            exit 0
            ;;
        -*)
            echo "$CMDNAME: invalid option: $1"
            exit 1
            ;;
        *)
            INFILE=$1
            ;;
    esac
    shift
done


if [ x"$INFILE" = x ] ; then
    echo "$CMDNAME: no input file"
    exit 1
fi

SORTEDFILE="$$-fmgr.data"
OIDSFILE=fmgroids.h
TABLEFILE=fmgrtab.c


trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15

#
# Collect the column numbers of the pg_proc columns we need.  Because we will
# be looking at data that includes the OID as the first column, add one to
# each column number.
#
proname=`egrep '^#define Anum_pg_proc_proname[ 	]' $INFILE | $AWK '{print $3+1}'`
prolang=`egrep '^#define Anum_pg_proc_prolang[ 	]' $INFILE | $AWK '{print $3+1}'`
proisstrict=`egrep '^#define Anum_pg_proc_proisstrict[ 	]' $INFILE | $AWK '{print $3+1}'`
proretset=`egrep '^#define Anum_pg_proc_proretset[ 	]' $INFILE | $AWK '{print $3+1}'`
pronargs=`egrep '^#define Anum_pg_proc_pronargs[ 	]' $INFILE | $AWK '{print $3+1}'`
prosrc=`egrep '^#define Anum_pg_proc_prosrc[ 	]' $INFILE | $AWK '{print $3+1}'`

#
# Generate the file containing raw pg_proc data.  We do three things here:
# 1. Strip off the DATA macro call, leaving procedure OID as $1
# and all the pg_proc field values as $2, $3, etc on each line.
# 2. Fold quoted fields to simple "xxx".  We need this because such fields
# may contain whitespace, which would confuse awk's counting of fields.
# Fortunately, this script doesn't need to look at any fields that might
# need quoting, so this simple hack is sufficient.
# 3. Select out just the rows for internal-language procedures.
#
# Note assumption here that INTERNALlanguageId == 12.
#
egrep '^DATA' $INFILE | \
sed 	-e 's/^[^O]*OID[^=]*=[ 	]*//' \
	-e 's/(//' \
	-e 's/"[^"]*"/"xxx"/g' | \
$AWK "\$$prolang == \"12\" { print }" | \
sort -n > $SORTEDFILE

if [ $? -ne 0 ]; then
    cleanup
    echo "$CMDNAME failed"
    exit 1
fi


cpp_define=`echo $OIDSFILE | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | sed -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`

#
# Generate fmgroids.h
#
cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf
/*-------------------------------------------------------------------------
 *
 * $OIDSFILE
 *    Macros that define the OIDs of built-in functions.
 *
 * These macros can be used to avoid a catalog lookup when a specific
 * fmgr-callable function needs to be referenced.
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * NOTES
 *	******************************
 *	*** DO NOT EDIT THIS FILE! ***
 *	******************************
 *
 *	It has been GENERATED by $CMDNAME
 *	from $INFILE
 *
 *-------------------------------------------------------------------------
 */
#ifndef $cpp_define
#define $cpp_define

/*
 *	Constant macros for the OIDs of entries in pg_proc.
 *
 *	NOTE: macros are named after the prosrc value, ie the actual C name
 *	of the implementing function, not the proname which may be overloaded.
 *	For example, we want to be able to assign different macro names to both
 *	char_text() and name_text() even though these both appear with proname
 *	'text'.  If the same C function appears in more than one pg_proc entry,
 *	its equivalent macro will be defined with the lowest OID among those
 *	entries.
 */
FuNkYfMgRsTuFf

tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $SORTEDFILE | \
$AWK "{ if (seenit[\$$prosrc]++ == 0)
	printf \"#define F_%s %s\\n\", \$$prosrc, \$1; }" >> "$$-$OIDSFILE"

if [ $? -ne 0 ]; then
    cleanup
    echo "$CMDNAME failed"
    exit 1
fi

cat >> "$$-$OIDSFILE" <<FuNkYfMgRsTuFf

#endif /* $cpp_define */
FuNkYfMgRsTuFf

#
# Generate fmgr's built-in-function table.
#
# Print out the function declarations, then the table that refers to them.
#
cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
/*-------------------------------------------------------------------------
 *
 * $TABLEFILE
 *    The function manager's table of internal functions.
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * NOTES
 *
 *	******************************
 *	*** DO NOT EDIT THIS FILE! ***
 *	******************************
 *
 *	It has been GENERATED by $CMDNAME
 *	from $INFILE
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "utils/fmgrtab.h"

FuNkYfMgRtAbStUfF

$AWK "{ if (seenit[\$$prosrc]++ == 0)
	print \"extern Datum\", \$$prosrc, \"(PG_FUNCTION_ARGS);\"; }" $SORTEDFILE >> "$$-$TABLEFILE"

if [ $? -ne 0 ]; then
    cleanup
    echo "$CMDNAME failed"
    exit 1
fi


cat >> "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF

const FmgrBuiltin fmgr_builtins[] = {
FuNkYfMgRtAbStUfF

# Note: using awk arrays to translate from pg_proc values to fmgrtab values
# may seem tedious, but avoid the temptation to write a quick x?y:z
# conditional expression instead.  Not all awks have conditional expressions.

$AWK "BEGIN {
    Bool[\"t\"] = \"true\";
    Bool[\"f\"] = \"false\";
}
{ printf (\"  { %d, \\\"%s\\\", %d, %s, %s, %s },\\n\"),
	\$1, \$$prosrc, \$$pronargs, Bool[\$$proisstrict], Bool[\$$proretset], \$$prosrc ;
}" $SORTEDFILE >> "$$-$TABLEFILE"

if [ $? -ne 0 ]; then
    cleanup
    echo "$CMDNAME failed"
    exit 1
fi

cat >> "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
  /* dummy entry is easier than getting rid of comma after last real one */
  /* (not that there has ever been anything wrong with *having* a
     comma after the last field in an array initializer) */
  { 0, NULL, 0, false, false, NULL }
};

/* Note fmgr_nbuiltins excludes the dummy entry */
const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;
FuNkYfMgRtAbStUfF

# We use the temporary files to avoid problems with concurrent runs
# (which can happen during parallel make).
mv "$$-$OIDSFILE" $OIDSFILE
mv "$$-$TABLEFILE" $TABLEFILE

cleanup
exit 0
