#! /bin/sh

# Convert templates into Makefile and config.c, 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.c template (default $srcdir/config.c.in)
# -c -:         don't write config.c
# -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.c.in to config.c:
# - insert an identifying comment at the start
# - for each <module> mentioned in Setup:
#   + 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, insert a rule
#   '<file>.o: <file>.c; <build commands>' before the comment
#   'Rules added by makesetup'
# - for each variable definition found in Setup, insert the definition
#   before the comment 'Definitions added by makesetup'

# Loop over command line options
usage='
usage: makesetup [-s srcdir] [-c config.c.in] [-m Makefile.pre]
                 [Setup] ... [-n [Setup] ...]'
srcdir=''
config=''
makepre=''
noobjects=''
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.c.in;;
esac
case $makepre in
'')	makepre=Makefile.pre;;
esac

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

# Main loop
for i in ${*-Setup}
do
	case $i in
	-n)	echo '<noobjects>';;
	*)	cat "$i";;
	esac
done |
sed -e 's/[ 	]*#.*//' -e '/^[ 	]*$/d' |
(
	DEFS=
	MODS=
	OBJS=
	LIBS=
	RULES=
	LOCALLIBS=
	BASELIBS=
	while read line
	do
		# Output DEFS in reverse order so first definition overrides
		case $line in
		*=*)	DEFS="$line$NL$DEFS"; continue;;
		'<noobjects>')
			case $noobjects in
			yes)	;;
			*)	LOCALLIBS=$LIBS; LIBS=;;
			esac
			noobjects=yes;
			continue;; 
		esac
		objs=
		srcs=
		cpps=
		set $line
		for arg
		do
			case $arg in
			-[IDUC]*)	cpps="$cpps $arg";;
			-[A-Zl]*)	LIBS="$LIBS $arg";;
			*.a)		LIBS="$LIBS $arg";;
			*.o)		objs="$objs $arg";;
			*.[cC])		srcs="$srcs $arg";;
			*.cc)		srcs="$srcs $arg";;
			*.c++)		srcs="$srcs $arg";;
			*.*)		echo 1>&2 "bad word $arg in $line"
					exit 1;;
			[a-zA-Z_]*)	MODS="$MODS $arg";;
			*)		echo 1>&2 "bad word $arg in $line"
					exit 1;;
			esac
		done
		case $noobjects in
		yes)	continue;;
		esac
		for obj in $objs
		do
		  src=`basename $obj .o`.c
		  case $src in
		  glmodule.c) ;;
		  *) src='$(srcdir)/'$src;;
		  esac
		  RULES="$RULES$obj: $src; \$(CC) \$(CFLAGS) $cpps -c $src$NL"
		done
		OBJS="$OBJS $objs"
		for src in $srcs
		do
		  case $src in
		  *.c)   obj=`basename $src .c`.o; cc='$(CC)';;
		  *.cc)  obj=`basename $src .cc`.o; cc='$(CCC)';;
		  *.c++) obj=`basename $src .c++`.o; cc='$(CCC)';;
		  *.C)   obj=`basename $src .C`.o; cc='$(CCC)';;
		  *)     continue;;
		  esac
		  case $src in
		  glmodule.c) ;;
		  *) src='$(srcdir)/'$src;;
		  esac
		  RULES="$RULES$obj: $src; $cc \$(CFLAGS) $cpps -c $src$NL"
		done
	done

	case $noobjects in
	yes)	BASELIBS=$LIBS;;
	*)	LOCALLIBS=$LIBS;;
	esac
	LIBS='$(LOCALMODLIBS) $(BASEMODLIBS)'
	DEFS="BASEMODLIBS=$BASELIBS$NL$DEFS"
	DEFS="LOCALMODLIBS=$LOCALLIBS$NL$DEFS"

	EXTDECLS=
	INITBITS=
	for mod in $MODS
	do
		EXTDECLS="${EXTDECLS}extern void init$mod();$NL"
		INITBITS="${INITBITS}	{\"$mod\", init$mod},$NL"
	done

	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.c
	    ;;
	esac

	case $makepre in
	-)  ;;
	*)  sed -e "
		1i$NL# Generated automatically from $makepre by makesetup.
		s%@MODOBJS@%$OBJS%
		s%@MODLIBS@%$LIBS%
		/Rules added by makesetup/a$NL$NL$RULES
		/Definitions added by makesetup/a$NL$NL$DEFS

		" $makepre >Makefile
	    ;;
	esac

)
