#! /bin/sh

# Convert templates into Makefile and config.cc, based on the module
# definitions found in the file Setup.
#
# Usage: makesetup [-s dir] [-c file] [-m file] [Setup] ... [-n [Setup] ...]
#
# Options:
# -s directory: alternative source directory (default derived from $0)
# -c file:      alternative config.cc template (default $srcdir/config.cc.in)
# -c -:         don't write config.cc
# -m file:      alternative Makefile template (default ./Makefile.pre)
# -m -:         don't write Makefile
#
# Remaining arguments are one or more Setup files (default ./Setup).
# Setup files after a -n option are used for their variables, modules
# and libraries but not for their .o files.
#
# See Setup.in for a description of the format of the Setup file.
#
# The following edits are made:
#
# Copying config.cc.in to config.cc:
# - insert an identifying comment at the start
# - for each <module> mentioned in Setup before *noconfig*:
#   + insert 'extern void init<module>();' before MARKER 1
#   + insert '{"<module>", initmodule},' before MARKER 2
#
# Copying Makefile.pre to Makefile:
# - insert an identifying comment at the start
# - replace _MODOBJS_ by the list of objects from Setup (except for
#   Setup files after a -n option)
# - replace _MODLIBS_ by the list of libraries from Setup
# - for each object file mentioned in Setup, append a rule
#   '<file>.o: <file>.c; <build commands>' to the end of the Makefile
# - for each module mentioned in Setup, append a rule
#   which creates a shared library version to the end of the Makefile
# - for each variable definition found in Setup, insert the definition
#   before the comment 'Definitions added by makesetup'

# Oct 13, 2003 -Fred Hansen- added 'extrainstall' feature
#   the Makefile template has a line "#ADDINSTALLS"
#   for each line in Setup file beginning with "extrainclude",
#   the rest of the line is appended to the install rule
#   at the point of the #ADDINSTALLS 

# Loop over command line options
usage='
usage: makesetup [-s srcdir] [-c config.cc.in] [-m Makefile.pre]
                 [Setup] ... [-n [Setup] ...]'
srcdir=''
config=''
makepre=''
noobjects=''
test='-'
default=''
doconfig=yes
while :
do
	case $1 in
	-s)	shift; srcdir=$1; shift;;
	-c)	shift; config=$1; shift;;
	-m)	shift; makepre=$1; shift;;
	--)	shift; break;;
	-n)	noobjects=yes;;
	-*)	echo "$usage" 1>&2; exit 2;;
	*)	break;;
	esac
done

# Set default srcdir and config if not set by command line
# (Not all systems have dirname)
case $srcdir in
'')	case $0 in
	*/*)	srcdir=`echo $0 | sed 's,/[^/]*$,,'`;;
	*)	srcdir=.;;
	esac;;
esac
case $config in
'')	config=$srcdir/config.cc.in;;
esac
case $makepre in
'')	makepre=Makefile.pre;;
esac

# Newline for sed i and a commands
NL='\
'

TAB='	'

cxxsrcs=config.cc
ccsrcs= 

# Main loop
for i in ${*-Setup}
do
	case $i in
	-n)	echo '*noobjects*';;
	*)	echo '*doconfig*'; cat "$i";;
	esac
done |
sed -e 's/[ 	]*#.*//' -e '/^[ 	]*$/d' |
(
	rulesf="@rules.$$"
	trap 'rm -f $rulesf' 0 1 2 3
	echo "
# Rules appended by makesetup
" >$rulesf
	DEFS=
	MODS=
	OBJS=
	LIBS=
        ELIBS=
	LOCALLIBS=
	DEPLIBS=
	EXPORTLIBS=
	BASELIBS=
	TESTS=
	INSTALLS=
        TARGETS=
	EXTRAINSTALLS=
	while read line
	do
		# Output DEFS in reverse order so first definition overrides
		case $line in
		*=*)	DEFS="$line$NL$DEFS"; continue;;
		'include '*)	DEFS="$line$NL$DEFS"; continue;;
		'extrainstall'*)
			EXTRAINSTALLS="$TAB${line#"extrainstall"}$NL$EXTRAINSTALLS"
			continue;;
                '*interface*'*) interface=${line#"*interface* "}; continue;;
                '*default*'*) default=${line#"*default* "}; continue;;
                '*test*'*) 
                        test=${line#"*test* "};
                        set $test; output=$1;
                        testflags=${test#$output}
                        rule="$output: ${output}.cc \$(LIB_NAME) \$(LIB_DEPENDS); \$(CXX) \$(CPPFLAGS) \$(CXXFLAGS) $output.cc -o $output \$(LIB_NAME) $testflags \$(USERLIBS) \$(LIBS)";
                        echo "$rule" >> $rulesf;
                        TESTS="${TESTS} ${output}"
                        cxxsrcs="$cxxsrcs ${output}.cc"
			continue;;
                '*ctest*'*) 
                        test=${line#"*ctest* "};
                        set $test; output=$1;
                        testflags=${test#$output}
                        rule="$output: ${output}.c \$(LIB_NAME) \$(LIB_DEPENDS); \$(CC) \$(CPPFLAGS) \$(CFLAGS) $output.c -o $output \$(LIB_NAME) $testflags \$(USERLIBS) \$(LIBS)";
                        echo "$rule" >> $rulesf;
                        TESTS="${TESTS} ${output}"
                        ccsrcs="$ccsrcs ${output}.c"
			continue;;
                '*install*'*) 
                        test=${line#"*install* "};
                        set $test; output=$1;
			INSTALLS="${output} ${INSTALLS}"
                        testflags=${test#$output}
                        rule="$output: ${output}.cc \$(LIB_NAME) \$(LIB_DEPENDS); \$(CXX) \$(CPPFLAGS) \$(CXXFLAGS) $output.cc -o $output \$(LIB_NAME) $testflags \$(USERLIBS) \$(LIBS)";
                        echo "$rule" >> $rulesf;
                        TESTS="${TESTS} ${output}"
                        cxxsrcs="$cxxsrcs ${output}.cc"
			continue;;
                '*target*'*) 
                        test=${line#"*target* "};
                        set $test; output=$1;
			TARGETS="${output} ${TARGETS}"
                        testflags=${test#$output}
                        rule="$output: ${output}.cc \$(LIB_NAME) \$(LIB_DEPENDS); \$(CXX) \$(CPPFLAGS) \$(CXXFLAGS) $output.cc -o $output \$(LIB_NAME) $testflags \$(USERLIBS) \$(LIBS)";
                        echo "$rule" >> $rulesf;
                        TESTS="${TESTS} ${output}"
                        cxxsrcs="$cxxsrcs ${output}.cc"
			continue;;
		'*noobjects*')
			case $noobjects in
			yes)	;;
			*)	LOCALLIBS=$LIBS; EXPORTLIBS=$ELIBS;
				ELIBS=; LIBS=;;
			esac
			noobjects=yes;
			continue;;
		'*doconfig*')	doconfig=yes; continue;;
		'*noconfig*')	doconfig=no; continue;;
		esac
                if test -z "$interface"; then
                    continue
                fi
                srcs=
		cpps=
		libs=
                explibs=
		mods=
		skip=
                extraobjs=
		for arg in $line
		do
			case $skip in
			libs)	libs="$libs $arg"; 
				explibs="$explibs $arg"; skip=; continue;;
			cpps)	cpps="$cpps $arg"; skip=; continue;;
			srcs)	srcs="$srcs $arg"; skip=; continue;;
                        objs)   extraobjs="$objs $arg"; skip=; continue;;
                        local)  libs="$libs $arg"; skip=; DEPLIBS="$DEPLIBS $arg"; continue;;
			export)	explibs="$explibs $arg"; skip=; continue;;
			esac
			case $arg in
			-[IDUC]*)	cpps="$cpps $arg";;
			-Xlinker)	libs="$libs $arg"; 
					explibs="$explibs $arg"; skip=libs;;
			-[A-Zl]*)	libs="$libs $arg"; 
					explibs="$explibs $arg";;
			*.a)		libs="$libs $arg"; 
					explibs="$explibs $arg";;
			*.so)		libs="$libs $arg"; 
					explibs="$explibs $arg";;
			*.sl)		libs="$libs $arg"; 
					explibs="$explibs $arg";;
			/*.o)		libs="$libs $arg"; 
					explibs="$explibs $arg";;
			*.o)	srcs="$srcs `basename $arg .o`.c";
                                ccsrcs="$ccsrcs `basename $arg .o`.c";;
			*.c)	srcs="$srcs $arg"; ccsrcs="$ccsrcs $arg";;
			*.C)	srcs="$srcs $arg"; cxxsrcs="$cxxsrcs $arg";;
			*.cc)	srcs="$srcs $arg"; cxxsrcs="$cxxsrcs $arg";;
			*.c++)	srcs="$srcs $arg"; cxxsrcs="$cxxsrcs $arg";;
			*.cxx)	srcs="$srcs $arg"; cxxsrcs="$cxxsrcs $arg";;
			*.cpp)	srcs="$srcs $arg"; cxxsrcs="$cxxsrcs $arg";;
			lib)  skip=libs;;
			cpp)  skip=cpps;;
                        obj)  skip=objs;;
			local) skip=local;;
			export) skip=export;;
			\$*)		libs="$libs $arg"; 
					explibs="$explibs $arg";
					cpps="$cpps $arg";;
			*.*)		echo 1>&2 "bad word $arg in $line"
					exit 1;;
			-u)		skip=libs; libs="$libs -u";;
			[a-zA-Z_]*)	mods="$mods $arg";;
			*)		echo 1>&2 "bad word $arg in $line"
					exit 1;;
			esac
		done
		case $doconfig in
		yes)
			LIBS="$LIBS $libs";
			ELIBS="$ELIBS $explibs";
			MODS="$MODS $mods";
			;;
		esac
		case $noobjects in
		yes)	continue;;
		esac
		objs=$extraobjs
		for src in $srcs
		do
                        flags='$(CPPFLAGS) $(CXXFLAGS)'
			case $src in
			*.c)   obj=`basename $src .c`.o; cc='$(CC)'; flags='$(CPPFLAGS) $(CFLAGS)'; ext='.c';;
			*.cc)  obj=`basename $src .cc`.o; cc='$(CXX)'; ext='.cc';;
			*.c++) obj=`basename $src .c++`.o; cc='$(CXX)'; ext='.c++';;
			*.C)   obj=`basename $src .C`.o; cc='$(CXX)'; ext='.C';;
			*.cxx) obj=`basename $src .cxx`.o; cc='$(CXX)'; ext='.cxx';;
			*.cpp) obj=`basename $src .cpp`.o; cc='$(CXX)'; ext='.cpp';;
			*)     continue;;
			esac
			objs="$objs $obj"
			case $src in
			glmodule.c) ;;
			/*) ;;
			*) src='$(srcdir)/'$src;;
			esac
			case $doconfig in
			no)	cc="$cc \$(CCSHARED)";;
			esac
			rule="$obj: $src; $cc $cpps $flags -c $src"
			echo "$rule" >>$rulesf
                        if test -n "$cpps"; then
                            dep=`basename $src $ext`.d
                            rule="$dep: $src; @echo 'Generating dependencies for $<';\$(subst %,$cpps,\$(CXXDEPPAT))"
                            echo "$rule" >>$rulesf
                        fi
		done
		case $doconfig in
		yes)	OBJS="$OBJS $objs";;
		esac
	done
        if test -r "${interface}.cc"; then
          OBJS="${interface}.o ${OBJS}"
	  cxxsrcs="$cxxsrcs ${interface}.cc"
        fi

	case $noobjects in
	yes)	BASELIBS=$LIBS;;
	*)	LOCALLIBS=$LIBS; EXPORTLIBS=$ELIBS;
	esac
	LIBS='$(LOCALMODLIBS) $(BASEMODLIBS)'
	DEFS="$DEFS$NL BASEMODLIBS=$BASELIBS"
	DEFS="$DEFS$NL LOCALMODLIBS=$LOCALLIBS"
	DEFS="$DEFS$NL EXPORTLIBS=$EXPORTLIBS"
	DEFS="$DEFS$NL INSTALLS=$INSTALLS"
	DEFS="$DEFS$NL BINTARGETS=$TARGETS"
	DEFS="$DEFS$NL LIB_DEPENDS+=$DEPLIBS"

	EXTDECLS=
	INITBITS=
	for mod in $MODS
	do
		EXTDECLS="${EXTDECLS}extern @TYPE@* create_${interface}_${mod}(__UTILS::Generator<@TYPE@>*,__UTILS::ConfigFile*,__UTILS::SymbolTable*);$NL"
		INITBITS="${INITBITS}	{\"${mod}\", create_${interface}_${mod}},$NL"
	done
        EXTDECLS="${EXTDECLS}#define DEFAULT_INTF \"${default}\"$NL"
	case $config in
	-)  ;;
	*)  sed -e "
		1i$NL/* Generated automatically from $config by makesetup. */
		/MARKER 1/i$NL$EXTDECLS

		/MARKER 2/i$NL$INITBITS

		" $config >config.tmp.cc
            sed -e "s%@TYPE[@]%$interface%g" config.tmp.cc > config.cc
            rm -f config.tmp.cc
	    ;;
	esac

	echo "CXXSRCS = $cxxsrcs \$(EXTRA_CXXSRCS)" >>$rulesf
	echo "CCSRCS = $ccsrcs \$(EXTRA_CCSRCS)" >>$rulesf
        echo "DSRCS = \$(CXXSRCS:.cc=.d) \$(CXXSRCS:.C=.d) \$(CXXSRCS:.cpp=.d) \$(CXXSRCS:.cxx=.d) \$(CCSRCS:.c=.d) " >> $rulesf

	echo "-include \$(filter %.d,\$(DSRCS))" >>$rulesf

	case $makepre in
	-)	;;
	*)	sedf="@sed.in.$$"
		trap 'rm -f $sedf' 0 1 2 3
		echo "1i\\" >$sedf
		str="# Generated automatically from $makepre by makesetup."
		echo "$str" >>$sedf
		echo "s%_MODOBJS_%$OBJS%" >>$sedf
		echo "s%_MODLIBS_%$LIBS%" >>$sedf
		echo "s%_MODTESTS_%$TESTS%" >>$sedf
		echo "s%_MODCXXSRCS_%$cxxsrcs%" >>$sedf
		echo "s%_MODCCSRCS_%$ccsrcs%" >>$sedf
		echo "s%_INTERFACE_NAME_%$interface%" >>$sedf
		echo "/#ADDINSTALLS/s%#ADDINSTALLS%$EXTRAINSTALLS%" >>$sedf
		echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf
		sed -f $sedf $makepre >Makefile
		cat $rulesf >>Makefile
		rm -f $sedf
	    ;;
	esac

	rm -f $rulesf
)
