# -*- sh -*-
# GSetup-Lib.sh
#		Library of routines for use by other scripts
#		Part of Generic SETUP
#
# Author	Stuart Herbert
#		(stuart@gnqs.org)
#
# Copyright	(c) 1998 Stuart Herbert
#		Released under v2 of the GNU GPL

# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////
# Global variables
# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////

export      GSETUP_V_DIR=../../../../SETUPDir/GSetup-Scripts
export             GSLIB=$GSETUP_V_DIR/GSetup-lib.sh

export       GPORT_V_DIR=$GSETUP_V_DIR/GPort-Scripts
export    GPORT_V_HEADER=GPort.h
export     GPORT_V_SHELL=./GPort-cache.sh
export      GPORT_V_MAKE=GPort.inc
export    GPORT_V_SOURCE=/dev/null

export V_ANSIC_F=0
export V_BSD43_F=0
export V_BSD44_F=0
export V_OTHER_F=0
export V_POSIX1_F=0
export V_POSIX2_F=0

export V_ANSIC_P=0
export V_BSD43_P=0
export V_BSD44_P=0
export V_OTHER_P=0
export V_POSIX1_P=0
export V_POSIX2_P=0

for x in $GCONFIG_V_SHELL $GPORT_V_SHELL $GMAKE_V_SHELL $GINSTALL_V_SHELL ./.gslib_tests ; do
	if [ -f $x ]; then
		. $x
	fi
done

# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////
# Functions to help setup internal library variables
# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////

# =-=-=-=-=
#	_F_ECHO ()
#
#	Configure echo support

_F_ECHO ()
{
	V_ECHO="echo"
	for x in /bin/echo /usr/bin/echo ; do
		if [ -f $x ]; then
			V_ECHO="$x"
		fi
	done

	if ($V_ECHO "testing\c" ; $V_ECHO "1,2,3") | grep c > /dev/null ; then
		# hrm ... \c isn't supported
		if ($V_ECHO -n "testing" ; $V_ECHO "1,2,3") | sed s/-n/xn/ | grep xn > /dev/null ; then
			# hrm ... -n isn't supported either
			# this is a total loss
			V_ECHO_N=
			V_ECHO_C=
			V_ECHO_T="	"
		else
			# -n is supported ... not a total loss
			V_ECHO_N=-n
			V_ECHO_C=
			V_ECHO_T="	"
		fi
	else
		# \c is supported ... not a total loss
		V_ECHO_N=
		V_ECHO_C='\c'
		V_ECHO_T="	"
	fi
}

# =-=-=-=-=
#	_F_INSERT_DESC_FILE ()
#
#	Insert a description file if one is available
#
#	$1	- variable to find a description file for

_F_INSERT_DESC_FILE ()
{
	if [ -f $GSLIB_V_DESC/$1.desc ]; then
		V_IFS="$IFS"
		IFS="
"
		
		echo "/*"	>> $GSLIB_V_HEADER

		cat $GSLIB_V_DESC/$1.desc | while read $V_INSERT_DESC ; do
			echo " * $V_INSERT_DESC"	>> $GSLIB_V_HEADER
			echo "# $V_INSERT_DESC"		>> $GSLIB_V_SHELL
		done

		echo "/*"	>> $GSLIB_V_HEADER
		echo		>> $GSLIB_V_HEADER
		echo		>> $GSLIB_V_SHELL
		IFS="$V_ISF"
	else
		F_DB F_WARNING "missing file $GSLIB_V_DESC/$1.desc"
	fi
}

# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////
# Library functions callable from elsewhere
# ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// ///// /////

# =-=-=-=-=
#	F_CHECK_HEADER ()
#
#	Check whether a specified header is present locally or not
#	Define GPORT_HAS_$1 appropriately

F_CHECK_HEADER ()
{
	F_ECHO_RESULT "Checking for <$1> ..."

	cat > test.c <<EOF

#include <$1>

int main (void)
{
	return 0;
}
EOF

	V_CHECK_HEADER="`echo $1 | tr './-' '___'`"
	F_COMPILE ctmp test.c
	case $? in
		0)	F_ECHO_LN "found it"
			F_DEFINE_BOOLEAN "GPORT_HAS_$V_CHECK_HEADER" 1
			F_TEST_PASSED
			return 0
			;;
		*)	F_ECHO_LN "not found"
			F_DEFINE_BOOLEAN "GPORT_HAS_$V_CHECK_HEADER" 0
			F_TEST_FAILED
			return 1
			;;
	esac
}

# =-=-=-=-=
#	F_CHECK_SIGNAL ()
#
#	Check whether a specified signal is present locally or not
#	Define GPORT_HAS_$1 appropriately
#
#	$1	- signal to check for

F_CHECK_SIGNAL ()
{
	F_ECHO_RESULT "Checking for $1 ... "

	cat > test.c <<EOF
#include <stdio.h>
#include <signal.h>

int main(void)
{
	printf ("%d", $1);
	return 0;
}
EOF

	F_COMPILE ctmp test.c
	case $? in
		0)	F_ECHO_LN "found it"
			F_DEFINE_BOOLEAN "GPORT_HAS_$1" 1
			F_TEST_PASSED
			return 0 ;;
		*)	F_ECHO_LN "not found"
			F_DEFINE_BOOLEAN "GPORT_HAS_$1" 0
			F_TEST_FAILED
			return 1 ;;
	esac
}

# =-=-=-=-=
#	F_COMPILE ()
#
#	Attempt to compile the specified script
#
#	$1	- compile|ctmp|link|run
#	$2	- script to compile
#	$3	- extra compiler flags
#	$4	- extra libraries

F_COMPILE ()
{
	if [ ! -f $2 ]; then
		F_WARNING "unable to find $2"
		return 127
	fi

	case $1 in
		link|run)     V_COMPILE="$GPORT_CC $3 -o test $2 $4" ;;
		compile|ctmp) V_COMPILE="$GPORT_CC $3 -o test.o -c $2" ;;
		*)            F_ERROR "unknown compile option '$2'"
			      exit 1 ;;
	esac

	echo "***"				>> gSETUP_compile.log
	echo "*** Running $V_COMPILE"		>> gSETUP_compile.log
	echo "***"				>> gSETUP_compile.log

#	$V_COMPILE 1>> gSETUP_compile.log 2>> gSETUP_compile.log
	V_output="`$V_COMPILE 2>&1`"
	V_x=$?
	echo "$V_output" >> gSETUP_compile.log

	echo "Compiler returned $V_x"		>> gSETUP_compile.log
	if [ "$V_output+" = "+" ]; then
		echo "No warnings or errors"	>> gSETUP_compile.log
	else
		echo "Warnings or errors"	>> gSETUP_compile.log
		V_x=255
	fi
	echo 					>> gSETUP_compile.log

	case $1 in
		compile)   rm -f test.o    ;;
		ctmp)	   rm -f $2 test.o ;;
		link)	   rm -f test      ;;
		run)       ./test ; rm -f test ;;
	esac

	return $V_x
}

# =-=-=-=-=
#	F_COMPILE_SCRIPT ()
#
#	Call F_COMPILE, using the name of the current script
#
#	For parameters, see F_COMPILE

F_COMPILE_SCRIPT ()
{
	F_COMPILE "$1" "${GSLIB_SCRIPT}.$2" "$3" "$4" "$5" "$6" "$7" "$8"
}

# =-=-=-=-=
#	F_DB ()
#
#	Execute the following command if debugging is enabled
#
#	$1 	- command to execute
#	$2 ...	- parameters to $1

F_DB ()
{
	if [ "$GSETUP_DEBUG+" != "+" ]; then
		"$@"
	fi
}

# =-=-=-=-=
#	F_DEFINE_BOOLEAN ()
#
#	Define a variable as being 0 or 1
#
#	$1	- variable name
#	$2	- value (0|1|y|Y|n|n)
#
#	Note: this function will load a description of the variable
#	from the file $GSLIB_V_DESC/$1.desc

F_DEFINE_BOOLEAN ()
{
	if [ "`echo eval $1`+" = "$2+" ]; then
		return
	fi

	_F_INSERT_DESC_FILE $1

	case $2 in
		1|y|Y)	V_DEFINE_BOOLEAN=1 ;;
		*)	V_DEFINE_BOOLEAN=0 ;;
	esac

	echo "#undef  $1"				>> $GSLIB_V_HEADER
	echo "#define $1 $V_DEFINE_BOOLEAN"		>> $GSLIB_V_HEADER
	echo						>> $GSLIB_V_HEADER
	echo "$1=$V_DEFINE_BOOLEAN"			>> $GSLIB_V_SHELL
	echo						>> $GSLIB_V_SHELL
	echo "{ \"$1\", \"$V_DEFINE_BOOLEAN\" },"	>> $GSLIB_V_SOURCE
	echo "$1=$V_DEFINE_BOOLEAN"			>> $GSLIB_V_MAKE
	echo						>> $GSLIB_V_MAKE

	. $GSLIB_V_SHELL

	expr `cat .gslib_def_count` + 1 > .gslib_def_count
}

# =-=-=-=-=
#	F_DEFINE_LITERAL
#
#	Define a variable as being an absolute string (ie no quotes)
#
#	$1	- variable name
#	$2	- value
#
#	Note: this function will load a description of the variable
#	from the file $GSLIB_V_DESC/$1.desc

F_DEFINE_LITERAL ()
{
	if [ "`echo eval $1`+" = "$2+" ]; then
		return
	fi

	_F_INSERT_DESC_FILE $1

	if [ "$2+" = "+" ]; then
		echo "#undef  $1"		>> $GSLIB_V_HEADER
		echo "$1="			>> $GSLIB_V_SHELL
	else
		echo "#undef  $1"		>> $GSLIB_V_HEADER
		echo "#define $1 $2"		>> $GSLIB_V_HEADER
		echo "$1=\"$2\""		>> $GSLIB_V_SHELL
		echo "$1=$2"			>> $GSLIB_V_MAKE
		echo "{ \"$1\", \"$2\" },"	>> $GSLIB_V_SOURCE
	fi

	echo					>> $GSLIB_V_HEADER
	echo					>> $GSLIB_V_SHELL

	. $GSLIB_V_SHELL

	expr `cat .gslib_def_count` + 1 > .gslib_def_count
}

# =-=-=-=-=
#	F_DEFINE_STRING
#
#	Define a variable as being an absolute string (ie no quotes)
#
#	$1	- variable name
#	$2	- value
#
#	Note: this function will load a description of the variable
#	from the file $GSLIB_V_DESC/$1.desc

F_DEFINE_STRING ()
{
	if [ "`echo eval $1`+" = "$2+" ]; then
		return
	fi

	_F_INSERT_DESC_FILE $1

	if [ "$2+" = "+" ]; then
		echo "#undef  $1"		>> $GSLIB_V_HEADER
		echo "$1="			>> $GSLIB_V_SHELL
	else
		echo "#undef  $1"		>> $GSLIB_V_HEADER
		echo "#define $1 \"$2\""	>> $GSLIB_V_HEADER
		echo "$1=\"$2\""		>> $GSLIB_V_SHELL
		echo "$1=$2"			>> $GSLIB_V_MAKE
		echo "{ \"$1\", \"$2\" },"	>> $GSLIB_V_SOURCE
	fi

	echo					>> $GSLIB_V_HEADER
	echo					>> $GSLIB_V_SHELL

	. $GSLIB_V_SHELL

	expr `cat .gslib_def_count` + 1 > .gslib_def_count
}

# =-=-=-=-=
#	F_ECHO ()
#
#	Echo a text string without a newline at the end
#
#	$1	- text to output

F_ECHO ()
{
	$V_ECHO $V_ECHO_N "$@$V_ECHO_C"
}

# =-=-=-=-=
#	F_ECHO_LN ()
#
#	Echo a text string with a newline at the end
#
#	$1	- text to output

F_ECHO_LN ()
{
	$V_ECHO "$@"
}

# =-=-=-=-=
#	F_ECHO_RESULT ()
#
#	Echo spaces to line up with the results column
#
#	$1	- string to echo

F_ECHO_RESULT ()
{
	V_ECHO_RESULT_x="$@"
	F_ECHO "${V_ECHO_RESULT_x}`F_ECHO_SPACE \"$V_ECHO_RESULT_x\"`   "
}

# =-=-=-=-=
#	F_ECHO_RESULT_LN ()
#
#	Echo spaces to line up with the results column, plus a newline
#
#	$1	- string to echo

F_ECHO_RESULT_LN ()
{
	F_ECHO_RESULT "$@"
	F_ECHO_LN
}

# =-=-=-=-=
#	F_ECHO_SEPARATOR ()
#
#	Echo a separator line
#
#	No parameters

F_ECHO_SEPARATOR ()
{
	F_ECHO_LN "-----------------------------------------------------------------------------"
}

# =-=-=-=-=
#	F_ECHO_SPACE ()
#
#	Echo the correct number of spaces required to pad the text out to
#	the Results column
#
#	$@	- text to be padded
#
#	Spaces are echoed to stdout

F_ECHO_SPACE ()
{
	# leading and trailing spaces are discounted by the length operator
	# so we must translate them first (sigh)
	#
	# why was something with as lovely a paradigm as the Bourne shell
	# also built with so many silly little stupidities?!?

	V_ECHO_SPACE_x="`echo \"$@\" | tr ' ' '.'`"

	# yes, this really is the fastest, most portable solution I could
	# think of ... feel free to suggest something faster
	#
	# and expr definitely isn't faster!

	case ${#V_ECHO_SPACE_x} in
		0) echo "                                        " ;;
		1) echo "                                       " ;;
		2) echo "                                      " ;;
		3) echo "                                     " ;;
		4) echo "                                    " ;;
		5) echo "                                   " ;;
		6) echo "                                  " ;;
		7) echo "                                 " ;;
		8) echo "                                " ;;
		9) echo "                               " ;;
		10) echo "                              " ;;
		11) echo "                             " ;;
		12) echo "                            " ;;
		13) echo "                           " ;;
		14) echo "                          " ;;
		15) echo "                         " ;;
		16) echo "                        " ;;
		17) echo "                       " ;;
		18) echo "                      " ;;
		19) echo "                     " ;;
		20) echo "                    " ;;
		21) echo "                   " ;;
		22) echo "                  " ;;
		23) echo "                 " ;;
		24) echo "                " ;;
		25) echo "               " ;;
		26) echo "              " ;;
		27) echo "             " ;;
		28) echo "            " ;;
		29) echo "           " ;;
		30) echo "          " ;;
		31) echo "         " ;;
		32) echo "        " ;;
		33) echo "       " ;;
		34) echo "      " ;;
		35) echo "     " ;;
		36) echo "    " ;;
		37) echo "   " ;;
		38) echo "  " ;;
		39) echo " " ;;
		*) ;;
	esac
}

# =-=-=-=-=
#	F_ERROR ()
#
#	Inform the user that a fatal error has occurred ...
#
#	$1	- error string to output

F_ERROR ()
{
	F_ECHO_LN "*** fatal error: $@"
}

# =-=-=-=-=
#	F_FIND_PATH ()
#
#	Search the user's current path for a specified binary, and
#	select the first one which matches the user's callback
#	requirements
#
#	$1	- binary to find
#	$2	- callback function
#
#	Returns
#
#	0	- success
#	1	- not found

F_FIND_PATH ()
{
	V_FIND_PATH_o="$1"
	V_FIND_PATH_c="$2"

	F_ECHO_RESULT "Checking \$PATH for '$1' ..."

	V_FIND_PATH_x="`F_SEARCH_PATH $1`"
	if [ "$V_FIND_PATH_x+" = "+" ]; then
		F_ECHO_LN "not found"
		return 1
	fi

	set $V_FIND_PATH_x

	if [ "$2+" != "+" ]; then
		F_ECHO_LN "found several matches"
		while [ "$1+" != "+" ]; do
			F_TEST_TYPE BLANK
			F_ECHO_RESULT
			F_ECHO_LN "found '$1'"
			shift
		done
	else
		F_ECHO_LN "found '$1'"
	fi

	set $V_FIND_PATH_x

	if [ "$V_FIND_PATH_c+" != "+" ]; then
		while [ "$1+" != "+" ]; do
			if $V_FIND_PATH_c $1 ; then
				GSLIB_V_ANSWER="$1"
				return 0
			fi
			shift
		done
		F_ECHO_LN
		F_WARNING "Cannot find a copy of '$V_FIND_PATH_o' which I like"
		return 1
	else
		F_TEST_TYPE BLANK
		F_ECHO_RESULT "  Decided to use ..."
		F_ECHO_LN "'$1'"
		GSLIB_V_ANSWER="$1"
		return 0
	fi
}

# =-=-=-=-=
#	F_SEARCH_PATH ()
#
#	Search the user's current path for a specified binary
#	Results are echoed to stdout
#	
#	$1	- binary to find

F_SEARCH_PATH ()
{
	for V_SEARCH_PATH_x in `echo $PATH | tr ':' ' '` ; do
		if [ -x "$V_SEARCH_PATH_x/$1" ]; then
			echo "$V_SEARCH_PATH_x/$1"
		fi
	done
}

# =-=-=-=-=
#	F_TEST_FAILED ()
#
#	The test we've just tried has failed

F_TEST_FAILED ()
{
	case $V_TEST_TYPE in
	ANSIC) 	echo "V_ANSIC_F=`expr $V_ANSIC_F + 1`"   >> ./.gslib_tests ;;
	BSD43)  echo "V_BSD43_F=`expr $V_BSD43_F + 1`"   >> ./.gslib_tests ;;
	BSD44)  echo "V_BSD44_F=`expr $V_BSD44_F + 1`"   >> ./.gslib_tests ;;
	OTHER)  echo "V_OTHER_F=`expr $V_OTHER_F + 1`"   >> ./.gslib_tests ;;
	POSIX1) echo "V_POSIX1_F=`expr $V_POSIX1_F + 1`" >> ./.gslib_tests ;;
	POSIX2) echo "V_POSIX2_F=`expr $V_POSIX2_F + 1`" >> ./.gslib_tests ;;
	*)	F_ECHO_LN
		F_ERROR "unknown test type '$V_TEST_TYPE'"
		exit 1
		;;
	esac

	. ./.gslib_tests
}

# =-=-=-=-=
#	F_TEST_PASSED ()
#
#	The test we have just conducted has passed
#
#	No parameters

F_TEST_PASSED ()
{
	case $V_TEST_TYPE in
	ANSIC) 	echo "V_ANSIC_P=`expr $V_ANSIC_P + 1`"   >> ./.gslib_tests ;;
	BSD43)  echo "V_BSD43_P=`expr $V_BSD43_P + 1`"   >> ./.gslib_tests ;;
	BSD44)  echo "V_BSD44_P=`expr $V_BSD44_P + 1`"   >> ./.gslib_tests ;;
	OTHER)  echo "V_OTHER_P=`expr $V_OTHER_P + 1`"   >> ./.gslib_tests ;;
	POSIX1) echo "V_POSIX1_P=`expr $V_POSIX1_P + 1`" >> ./.gslib_tests ;;
	POSIX2) echo "V_POSIX2_P=`expr $V_POSIX2_P + 1`" >> ./.gslib_tests ;;
	*)	F_ECHO_LN
		F_ERROR "unknown test type '$V_TEST_TYPE'"
		exit 1
		;;
	esac

	. ./.gslib_tests
}

# =-=-=-=-=
#	F_TEST_TYPE ()
#
#	Echo test type out to screen
#
#	$1	- POSIX1|POSIX2|BSD43|BSD44|OTHER|ANSIC

F_TEST_TYPE ()
{
	case $1 in
		ANSIC)  F_ECHO "ANSI C   " ;;
		BSD43)  F_ECHO "BSD 4.3  " ;;
		BSD44)  F_ECHO "BSD 4.4  " ;;
		OTHER)  F_ECHO "Other    " ;;
		POSIX1) F_ECHO "POSIX.1  " ;;
		POSIX2) F_ECHO "POSIX.2  " ;;
		BLANK)  F_ECHO "         " ; return ;;
		*)	F_ECHO_LN
			F_ERROR "unknown test type $1"
			exit 1
			;;
	esac

	V_TEST_TYPE=$1
}

# =-=-=-=-=
#	F_WARNING ()
#
#	Inform the user about a non-fatal problem
#
#	$1	- warning string to output

F_WARNING ()
{
	F_ECHO_LN "*** warning: $@"
}

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

_F_ECHO
