# Auxiliary functions for build.sh
# Copyright (c) 2002 Serge van den Boom
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# Show usage information
usage() {
	echo "Main build script"
	echo
	echo "Syntax:"
	echo "    ./build.sh <target>"
	echo "    ./build.sh <target> config"
	echo "    ./build.sh <target> depend"
	echo "    ./build.sh <target> clean"
	echo "    ./build.sh <target> install"
	echo "    ./build.sh cleanall"
	echo "    ./build.sh distclean"
	echo
	echo "Valid targets:"
	for TARGET in $TARGETS; do
		echo "    $TARGET"
	done
	echo
}

escape_string() {
	$SED -e s,[\\\'\"\`\	\ \$\&\\\*\\\?\#\!],\\\\\&,g << EOF
$1
EOF
}

# The actual recursing function
build_recurse() {
	local FILES SUBDIRS
	# Perform an action for this dir
	eval FILES="\${$BUILD_FILES_VAR}"
	for FILE in $FILES; do
		$BUILD_REC_COMMAND "$BUILD_REC_PATH$FILE"
	done

	# Recurse for all subdirs
	eval SUBDIRS="\$${BUILD_PROJECT}_SUBDIRS"
	for DIR in $SUBDIRS; do
		BUILD_REC_PATH="$BUILD_REC_PATH$DIR/" $SH "$0"
		$BUILD_REC_DIR_COMMAND "$BUILD_REC_PATH$DIR"
	done
}

# Start the recursion
build_do_recursive() {
	BUILD_COMMAND=build_recurse
	BUILD_REC_COMMAND="$1"
	BUILD_REC_DIR_COMMAND="$2"
	export BUILD_COMMAND BUILD_REC_COMMAND BUILD_REC_DIR_COMMAND
	build_recurse
}

# Build dependency information for one file
build_dependencies() {
	eval $ECHON \$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}\$BUILD_REC_PATH
	eval eval \\\$MKDEPEND \"\${${BUILD_PROJECT}_CFLAGS}\" \"\\\$1\" | \
			grep -v '#'
}

# Recursively build dependency information
build_rec_dependencies() {
	local DEPEND_FILE EXTRA_OFILES

	echo "Building dependency information..." >&2
	
	BUILD_WORK_ESC=`escape_string "$BUILD_WORK"`
	export BUILD_WORK_ESC

	eval mkdir -p "\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}"
	eval DEPEND_FILE="\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}.depend"

	# Remove the old dependency file, if it exists.
	# The .tmp file is used to detect interrupted dependency builds.
	rm -f -- "$DEPEND_FILE".tmp "$DEPEND_FILE"

	BUILD_FILES_VAR=${BUILD_PROJECT}_EXTRA_OFILES
	export BUILD_FILES_VAR
	EXTRA_OFILES=`build_do_recursive build_collect_extra_o_files :`

	BUILD_FILES_VAR=${BUILD_PROJECT}_CFILES
	OFILES=`build_do_recursive build_collect_o_files :`

	{
		eval $ECHON "\$BUILD_WORK_ESC/target-\${${BUILD_PROJECT}_NAME}:"
		for OFILE in $OFILES $EXTRA_OFILES; do
			$ECHON " $OFILE"
		done
		echo
		build_do_recursive build_dependencies :
	} > "$DEPEND_FILE".tmp
	mv -f -- "$DEPEND_FILE".tmp "$DEPEND_FILE"
}

# Output the .o file for a given .c or .m (Objective-C) file
build_collect_o_files() {
	eval echo "\$BUILD_WORK_ESC/\${${BUILD_PROJECT}_OBJS}\${1%.[cm]}.o"
}

# Output the extra .o file with the complete path
build_collect_extra_o_files() {
	eval echo "\$BUILD_WORK_ESC/\${${BUILD_PROJECT}_OBJS}\$1"
}

# Recursively collect .o-files
build_rec_collect_o_files() {
	local EXTRA_OFILES

	BUILD_WORK_ESC=`escape_string "$BUILD_WORK"`
	export BUILD_WORK_ESC

	BUILD_FILES_VAR=${BUILD_PROJECT}_CFILES
	export BUILD_FILES_VAR
	build_do_recursive build_collect_o_files :

	BUILD_FILES_VAR=${BUILD_PROJECT}_EXTRA_OFILES
	build_do_recursive build_collect_extra_o_files :
}

# Start the configure program.
# $1 = target
build_config() {
	prepare_build_system
	config_requirements
	prepare_host_system
	if [ "$BUILD_SYSTEM" '!=' "$HOST_SYSTEM" ]; then
		build_message "Cross-compiling to $HOST_SYSTEM."
	fi
	eval "${TARGET}_requirements"
	eval "${TARGET}_prepare_config"
	eval "${TARGET}_load_config"
	eval "${TARGET}_do_config"
	eval "${TARGET}_save_config"
}

build_reconfig() {
	if [ ! -e "$BUILD_WORK/config.state" ]; then
		echo "*** Warning: file 'config.state' not found - using defaults."
	fi

	prepare_build_system
	config_requirements
	prepare_host_system
	if [ "$BUILD_SYSTEM" '!=' "$HOST_SYSTEM" ]; then
		build_message "Cross-compiling to $HOST_SYSTEM."
	fi
	eval "${TARGET}_requirements"
	eval "${TARGET}_prepare_config"
	eval "${TARGET}_load_config"
	build_process_config

	echo "Reconfiguring complete..." >&2
}

# Process the configuration information
build_process_config() {
	eval "${TARGET}_process_config"
}

# Compile the lot.
# With the depend info set up, we can leave everything to make.
build_compile() {
	eval "${TARGET}_pre_build"
	eval CFLAGS="\${${BUILD_PROJECT}_CFLAGS}" \
			LDFLAGS="\${${BUILD_PROJECT}_LDFLAGS}" \
			DEPEND_FILE="\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}.depend" \
			\$MAKE -f Makefile.build \"\$BUILD_WORK/target-\${${BUILD_PROJECT}_NAME}\"
	eval "${TARGET}_post_build"
}

# Description: Remove the .o file for one .c file
# Arguments:   $1 - the .c file
build_clean_file() {
	eval rm -f -- "\"\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}\${1%.c}.o\""
}

build_clean_dir() {
	eval rmdir -- "\"\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}\${1}\"" 2> /dev/null
	return 0
}

build_clean() {
	local DEPEND_FILE
	eval DEPEND_FILE="\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}.depend"
	rm -f "$DEPEND_FILE" "$BUILD_WORK/build.vars" \
			"$BUILD_WORK/config.state" "$BUILD_WORK/config_unix.h"
	BUILD_FILES_VAR=${BUILD_PROJECT}_CFILES
	export BUILD_FILES_VAR
	build_do_recursive build_clean_file build_clean_dir
}

build_cleanall() {
	export BUILD_PROJECT
	for TARGET in $TARGETS; do
		BUILD_PROJECT="$TARGET"
		build_clean
	done
	BUILD_PROJECT=""
}

build_distclean() {
	build_cleanall
}


# Description: check if the config files are present and load them.
#              If they're not present, remake them.
build_check_config() {
	if [ ! -e "$BUILD_WORK/build.vars" ]; then
		build_config || exit $?
		build_process_config
	fi
	. "$BUILD_WORK/build.vars"
	. "${BUILD_REC_PATH:=./}Makeinfo"
}

# Description: check if the necessary .depend file is present,
#              if not, build it.
build_check_dependencies() {
	eval DEPEND_FILE="\$BUILD_WORK/\${${BUILD_PROJECT}_OBJS}.depend"
	[ ! -e "$DEPEND_FILE" -o -n "$BUILD_RUN_DEPEND" ] || return

	build_rec_dependencies || exit $?
}

# Description: check if the program is compiled, and otherwise compile
build_check_compile() {
	local NAME
	eval NAME="\${${BUILD_PROJECT}_NAME}"
	[ ! -e "$NAME" ] || return

	build_compile || exit $?
}

# Make a directory path, with mode and owner specified.
# $1 - name of directory path
# $2 - mode of the directories (may be empty)
# $3 - owner of the directories (may be empty)
mkdirhier() {
	local REST DIR MODE OWNER
	REST="$1"
	MODE="$2"
	OWNER="$3"
	case "$REST" in
		/*)
			REST="${REST%/}"
			DIR="/"
			;;
		*)
			DIR=""
			;;
	esac
	case "$REST" in
		*/)
			;;
		*)
			REST="${REST}/"
			;;
	esac
	while [ -n "$REST" ]; do
		DIR="$DIR${REST%%/*}"
		REST="${REST#*/}"
		if [ ! -d "$DIR" ]; then
			mkdir "$DIR"
			[ -n "$MODE" ] && chmod "$MODE" "$DIR"
			[ -n "$OWNER" ] && chown "$OWNER" "$DIR"
		fi
		DIR="${DIR}/"
	done
}

# Install a file or directory
# $1 - Source file/directory
# $2 - Destination directory/file
# $3 - Mode of destination file/directory
# $4 - Owner of destination file/directory
installsome() {
	local SRC DEST MODE OWNDER DESTDIR SRCNAME
	SRC="$1"
	DEST="$2"
	MODE="$3"
	OWNDER="$4"

	DESTDIR="${DEST%/*}"
	if [ ! -d "$DESTDIR" ]; then
		mkdirhier "$DESTDIR" 0755
	fi
	SRCNAME="${SRC##*/}"
	cp -pr -- "$SRC" "$DEST"
	if [ -n "$MODE" ]; then
		if [ -d "$DEST" ]; then
			chmod -R "$MODE" "${DEST}${SRCNAME}"
		else
			chmod "$MODE" "$DEST"
		fi
	fi
	if [ -n "$OWNER" ]; then
		if [ -d "$DEST" ]; then
			chown -R "$OWNER" "${DEST}${SRCNAME}"
		else
			chown "$OWNER" "$DEST"
		fi
	fi
}

# Install the program
build_install() {
	eval "${TARGET}_install"
}

# Generic installation routine
generic_install() {
	local SRC DEST MODE OWNER
	
	eval "${TARGET}_pre_install"

	local LIB LIBS LIBDIR
	echo "Installing system-dependent data..." >&2
	eval LIBS="\${${BUILD_PROJECT}_INSTALL_LIBS}"
	eval LIBDIR="\${${BUILD_PROJECT}_INSTALL_LIBDIR%/}/"
	mkdirhier "$LIBDIR" 0755
	for LIB in $LIBS; do
		eval SRC="\${${BUILD_PROJECT}_INSTALL_LIB_${LIB}_SRC%/}"
		eval DEST="\$LIBDIR\${${BUILD_PROJECT}_INSTALL_LIB_${LIB}_DEST}"
		eval MODE="\${${BUILD_PROJECT}_INSTALL_LIB_${LIB}_MODE}"
		eval OWNER="\${${BUILD_PROJECT}_INSTALL_LIB_${LIB}_OWNER}"
		installsome "$SRC" "$DEST" "$MODE" "$OWNER"
	done

	local SHARE SHARED SHAREDIR
	echo "Installing system-independent data..." >&2
	eval SHARED="\${${BUILD_PROJECT}_INSTALL_SHARED}"
	eval SHAREDIR="\${${BUILD_PROJECT}_INSTALL_SHAREDIR%/}/"
	mkdirhier "$SHAREDIR" 0755
	for SHARE in $SHARED; do
		eval SRC="\${${BUILD_PROJECT}_INSTALL_SHARED_${SHARE}_SRC%/}"
		eval DEST="\$SHAREDIR\${${BUILD_PROJECT}_INSTALL_SHARED_${SHARE}_DEST}"
		eval MODE="\${${BUILD_PROJECT}_INSTALL_SHARED_${SHARE}_MODE}"
		eval OWNER="\${${BUILD_PROJECT}_INSTALL_SHARED_${SHARE}_OWNER}"
		installsome "$SRC" "$DEST" "$MODE" "$OWNER"
	done

	local BINS BINDIR
	echo "Installing binaries..." >&2
	eval BINS="\${${BUILD_PROJECT}_INSTALL_BINS}"
	eval BINDIR="\${${BUILD_PROJECT}_INSTALL_BINDIR%/}/"
	mkdirhier "$BINDIR" 0755
	for BIN in $BINS; do
		eval SRC="\${${BUILD_PROJECT}_INSTALL_BIN_${BIN}_SRC%/}"
		eval DEST="\$BINDIR\${${BUILD_PROJECT}_INSTALL_BIN_${BIN}_DEST}"
		eval MODE="\${${BUILD_PROJECT}_INSTALL_BIN_${BIN}_MODE}"
		eval OWNER="\${${BUILD_PROJECT}_INSTALL_BIN_${BIN}_OWNER}"
		installsome "$SRC" "$DEST" "$MODE" "$OWNER"
	done

	eval "${TARGET}_post_install"
}


