#!/bin/sh
#
# Configuration script for Cygnus & OperStats

# Nifty handy functions.

echo2 () {
	$ECHO2 "$*$ECHO2SUF"
}

run () {
	$* >&3 2>&3 </dev/null
}

exists () {
	if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then
		return 0
	else
		return 1
	fi
}

test_function () {
	rettype="$1"
	func="$2"
	proto="$3"
	if [ ! "$rettype" -o ! "$func" ] ; then
		return 1
	fi
	if [ ! "$proto" ] ; then
		proto="(...)"
	fi
	func2=`echo $func | tr '[a-z]' '[A-Z]'`
	if [ ! "$TEST" ] ; then
		TEST="return 0;"
	fi
	cat >tmp/test.c <<EOT
	int main() {
		extern int $func$proto;
		$TEST
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test && run tmp/test ; then
		eval "HAVE_${func2}=1"
		return 0
	else
		eval "HAVE_${func2}=0"
		return 1
	fi
}

# Create a temporary directory for our use.

if [ -d tmp ] ; then
	rm -rf tmp
fi
if mkdir tmp ; then : ; else
	echo "Failed to create temporary directory! Exiting."
	exit 2
fi
if chmod u+rwx tmp ; then : ; else
	echo "Cannot write to temporary directory! Exiting."
	exit 2
fi

# Variable initialization.

PACKAGE="OperStats"
FULLPACKAGE=$PACKAGE
SERVICES_DIR="OPERSTATS_DIR"
SERVICES_BINARY="OS_BINARY"
COPYRIGHT="2000-2003"
CONFFILE="operstats.conf"
BINARY="operstats"

COMPILERFLAGS="-O3 -Wall -Wshadow -g"

DEST="$HOME/operstats"
CONVERT="0"

INSTALL=
CC=
CC_FLAGS=flibble
CC_LIBS=flibble

TYPE_INT8=
TYPE_INT16=
TYPE_INT32=
TYPE_INT64=

HAVE_STRERROR=
HAVE_SYS_ERRLIST=0
HAVE_GETHOSTBYNAME=
HAVE_LCRYPT=
HAVE_GETTIMEOFDAY=
HAVE_UMASK=
MISSING=flibble

# How can we echo something without going to the next line?

ECHO2SUF=''
if [ "`echo -n a ; echo b`" = "ab" ] ; then
	ECHO2='echo -n'
elif [ "`echo 'a\c' ; echo 'b'`" = "ab" ] ; then
	ECHO2='echo' ; ECHO2SUF='\c'
elif [ "`printf 'a' 2>&1 ; printf 'b\n' 2>&1`" = "ab" ] ; then
	ECHO2='printf "%s"'
else
	ECHO2='echo'
fi
export ECHO2 ECHO2SUF

# Header

clear
echo "$FULLPACKAGE -- Copyright (c) $COPYRIGHT Darcy Grexton"
echo ""
echo "Although these services are completely free and open source, I do accept"
echo "donations. If you would like to donate to help me continue my work on $PACKAGE"
echo "and other projects I maintain, see the doc/DONATE file. Thank you."
echo ""
echo "Press enter to begin configuration."
echo2 ""
if read INPUT ; then : ; else echo "" ; exit 1 ; fi

# Command-line parsing.

IGNORE_CACHE= ; USER_CC= ; USER_CC_FLAGS=flibble ; USER_CC_LFLAGS=flibble ; USER_CC_LIBS=
export IGNORE_CACHE USER_CC USER_CC_FLAGS USER_CC_LFLAGS USER_CC_LIBS

while [ $# -gt 0 ] ; do
	if [ "$1" = "-ignore-cache" ] ; then
		IGNORE_CACHE=flibble
	elif [ "$1" = "-cc" ] ; then
		shift
		USER_CC=$1
	elif [ "$1" = "-cflags" ] ; then
		shift
		USER_CC_FLAGS=$1
	elif [ "$1" = "-lflags" ] ; then
		shift
		USER_CC_LFLAGS=$1
	elif [ "$1" = "-libs" ] ; then
		shift
		USER_CC_LIBS=$1
	else
		if [ "$1" != "-help" ] ; then
			echo >&2 Unknown option/parameter: "$1"
		fi
		cat >&2 <<EOT
Available options:
	-ignore-cache  Don't use cache file if it exists
	-cc            Specify C compiler to use (overrides cache and check)
	-cflags        Specify compilation flags (defaults: -O3 for gcc,
	               -O for other compilers; overrides cache/check)
	-lflags        Specify link flags for C compiler (default: none)
	-libs          Specify extra link libraries to use (default: none)
EOT
		exit 1
	fi
	shift
done

# First, test for the presence of a configure.cache file.  If found, either
# don't use it (-ignore-cache), or let the user know how to not use it and
# then use it.

if [ -f configure.cache -a -r configure.cache -a ! "$IGNORE_CACHE" ] ; then
	cat <<EOT
Using defaults from configure.cache. To ignore, either remove configure.cache
or give the command-line option "-ignore-cache".

EOT
	. configure.cache
	MISSING=flibble
fi

export ok INPUT

if [ -f doc/RELEASE ] ; then
	ok=0
	echo "Would you like to read the release notes (Recommended)?"
	while [ $ok -eq 0 ] ; do
		echo2 "[Yes] "
		if read INPUT ; then : ; else echo "" ; exit 1 ; fi
		if [ ! "$INPUT" ] ; then
			echo ""
			more doc/RELEASE
			echo ""
			echo "-----"
			ok=1
		fi
		case $INPUT in
			[Yy]*)
				echo ""
				more doc/RELEASE
				ok=1
				;;
			[Nn]*)
				ok=1
				;;
		esac
	done
	echo ""
fi

ok=0
echo "Where do you want $PACKAGE to be installed?"
echo "Press enter for the default, or type a new destination."
while [ $ok -eq 0 ] ; do
	echo2 "[$DEST] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$DEST
	fi
	if [ ! -d "$INPUT" ] ; then
		if exists "$INPUT" ; then
			echo "$INPUT exists, but is not a directory!"
		else
			echo "$INPUT does not exist.  Create it?"
			echo2 "[Y] "
			read YN
			if [ "$YN" != "n" ] ; then
				if mkdir $INPUT ; then
					ok=1
				fi
			fi
		fi
	else
		ok=1
	fi
done
DEST=$INPUT
echo ""

if [ "$CONVERT" = "1" ] ; then
	CONV=Yes
else
	CONV=No
fi

if [ "$PACKAGE" = "Cygnus" ] ; then
	ok=0
	echo "Are you switching from another services package? We can convert your old"
	echo "databases so Cygnus can use them. Currently, Cygnus can convert the"
	echo "following databases:"
	echo "    WreckedNet Services v1.2.0"
	echo "    IRCServices 4.5.x"
	echo "    SirvNET Services 2.9.0"

	while [ $ok -eq 0 ] ; do
		echo2 "[$CONV] "
		if read INPUT ; then : ; else echo "" ; exit 1 ; fi
		if [ ! "$INPUT" ] ; then
			INPUT=$CONV
		fi
		case $INPUT in
			no\ default)
				ok=1
				;;
			y*|Y*)
				CONVERT="1"
				ok=1
				;;
			n*|N*)
				CONVERT="0"
				ok=1
				;;
		esac
	done
	echo ""
fi

exec 3>/dev/null

TEST=""
export TEST

# Search for a compiler.

echo2 "Checking for a usable compiler ...          "
if [ "$USER_CC" ] ; then
	CC="$USER_CC"
	echo "Found: $CC (User Supplied)"
elif [ "$CC" ] ; then
	echo "Found: $CC (Cached)"
elif run gcc --version ; then
	echo "Found: gcc"
	CC=gcc
	DEF_CC_FLAGS=$COMPILERFLAGS
else
	echo >tmp/test.c "int main(){return 1;}"
	if run cc tmp/test.c -o tmp/test ; then
		echo "Found: cc"
		CC=cc
	elif run c89 tmp/test.c -o tmp/test ; then
		echo "Found: c89"
		CC=c89
	else
		echo ""
		echo "No C compiler found!"
		echo "    Use the -cc command line option to specify your C compiler."
		exit 2
	fi
	# See if it handles ANSI.
	cat >tmp/test.c <<EOT
	int main(int argc, char **argv) {
		extern void foo(int bar);
	}
EOT
	echo2 "Checking for ANSI compliance ...            "
	if run $CC tmp/test.c -o tmp/test ; then
		echo "Passed"
	else
		echo "Failed"
		echo "Your compiler is not ANSI compliant."
		echo "    Use the -cc command line option to specify your C compiler."
		exit 2
	fi
	DEF_CC_FLAGS=$COMPILERFLAGS
fi

# Test compiler options.

if [ "$USER_CC_FLAGS" != flibble ] ; then
	CC_FLAGS="$USER_CC_FLAGS"
else
	CC_FLAGS=$COMPILERFLAGS
	echo2 "Testing compiler flags ...                  "
	cat >tmp/test.c <<EOT
	int main(int argc, char **argv) {
		extern void foo(int bar);
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c -o tmp/test ; then
		echo "Passed: $CC_FLAGS"
	else
		echo "Failed: $CC_FLAGS"
		echo "    If you know what flags you want, use the -cflags option to configure."
		CC_FLAGS=
	fi
fi

if [ "$USER_CC_LFLAGS" != "flibble" ] ; then
	CC_LFLAGS=$USER_CC_LFLAGS
fi

# See what libraries we have that we might need.

echo2 "Checking for libraries ...                  "
foundlibs=0
if [ "$CC_LIBS" != flibble ] ; then
	if [ "$CC_LIBS" ] ; then
		echo "$CC_LIBS (Cached)"
	else
		echo "none (Cached)"
	fi
else
	CC_LIBS=
        if run $CC $CC_FLAGS tmp/test.c -lcrypt -o tmp/test ; then         
                CC_LIBS="$CC_LIBS -lcrypt"
                echo2 "-lcrypt "
                foundlibs=1
		HAVE_LCRYPT=1
        fi
	if [ $foundlibs -eq 0 ] ; then
		echo "None"
	else
		echo ""
	fi
	CC_LIBS="`echo $CC_LIBS | sed 's/^ +//'`"
fi
if [ "$USER_CC_LIBS" ] ; then
	CC_LIBS="$CC_LIBS $USER_CC_LIBS"
	echo "Additional user-supplied libraries: $USER_CC_LIBS"
fi

echo2 "Checking for an 8-bit integer type ...      "
if [ "$TYPE_INT8" ] ; then
	echo "$TYPE_INT8 (Cached)"
else
	cat >tmp/test.c <<EOT
	int main() {
		char a;
		printf("%d", sizeof(a));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		if [ $a = 1 ] ; then
			echo char
			TYPE_INT8=char
		else
			echo "Assuming char"
			TYPE_INT8=char
		fi
	fi
fi

echo2 "Checking for a 16-bit integer type ...      "
if [ "$TYPE_INT16" ] ; then
	echo "$TYPE_INT16 (Cached)"
else
	cat >tmp/test.c <<EOT
	int main() {
		int a;
		short b;
		printf("%d %d", sizeof(a), sizeof(b));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		size_int=`echo $a | cut -d\  -f1`
		size_short=`echo $a | cut -d\  -f2` 
		if [ $size_int = 2 ] ; then
			echo int
			TYPE_INT16=int
		elif [ $size_short = 2 ] ; then 
			echo short
			TYPE_INT16=short
		else
			echo "Assuming short"
			TYPE_INT16=short
		fi
	fi
fi

echo2 "Checking for a 32-bit integer type ...      "
if [ "$TYPE_INT32" ] ; then
	echo "$TYPE_INT32 (Cached)"
else
	cat >tmp/test.c <<EOT
	int main() {
		int a;
		long b;
		printf("%d %d", sizeof(a), sizeof(b));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		size_int=`echo $a | cut -d\  -f1`
		size_long=`echo $a | cut -d\  -f2` 
		if [ $size_int = 4 ] ; then
			echo int
			TYPE_INT32=int
		elif [ $size_long = 4 ] ; then 
			echo long 
			TYPE_INT32=long 
		else
			echo "Assuming long"
			TYPE_INT32=long
		fi
	fi
fi

echo2 "Checking for a 64-bit integer type ...      "
if [ "$TYPE_INT64" ] ; then
	echo "$TYPE_INT64 (Cached)"
else
	cat >tmp/test.c <<EOT
	int main() {
		long long a;
		printf("%d", sizeof(a));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		if [ $a = 8 ] ; then
			echo "long long"
			TYPE_INT64="long long"
		else
			echo "None found. Using 32 bit."
			TYPE_INT64=TYPE_INT32
		fi
	fi
fi

# Look for missing/broken built-in routines, and similar compatibility
# stuff.

echo2 "Checking for things you don't have ...      "

if [ "$MISSING" != flibble ] ; then
        if [ ! "$MISSING" ] ; then
                echo "none (Cached)"
        else
                echo "$MISSING (Cached)"
        fi
else
        MISSING=

        TEST="char buf[256]; (void) gettimeofday((void *)buf, (void *)buf); return 0;"
        if test_function "char *" gettimeofday "(void *, void *)" ; then : ; else
                MISSING="$MISSING gettimeofday"
                echo2 "gettimeofday "
        fi
                  
        TEST="(void) umask(1); return 0;"
        if test_function int umask "(int)" ; then : ; else
                MISSING="$MISSING umask"
                echo2 "umask "
        fi

        TEST='(void) gethostbyname("localhost"); return 0;'
        if test_function "struct hostent *" gethostbyname "(const char *)" ; then : ; else
                MISSING="$MISSING gethostbyname"
                echo2 "gethostbyname "
        fi

        if [ !$HAVE_GETHOSTBYNAME -a !$HAVE_UMASK -a !$HAVE_GETTIMEOFDAY ] ; then    
                echo "none."
        else
                echo ""
        fi
fi

if [ $HAVE_GETHOSTBYNAME = 0 ] ; then
	cat <<_EOT_

*** Notice: Your system does not seem to have the gethostbyname() function.
*** This function is used to translate hostnames into IP addresses. Since 
*** you don't have it (or we can't find it), you will need to use IP
*** addresses instead of hostnames when setting the uplink server address
*** in $CONFFILE.

_EOT_
fi

if [ $HAVE_LCRYPT = 0 -a $PACKAGE = "Cygnus" ] ; then
	cat <<_EOT_

*** Notice: Your system does not seem to have lcrypt. If you use web
*** integration, all of your passwords will be stored as PLAIN TEXT.

_EOT_
fi

# Create files.

echo2 "Creating sysconf.h ...                      "
cat >inc/sysconf.h <<_EOT_
/* This file is generated automatically by "configure".  Any changes made
   to it will be erased next time "configure" is run.
 */

#define $SERVICES_DIR		"$DEST"
#define $SERVICES_BINARY		"$DEST/$BINARY"

#define HAVE_GETTIMEOFDAY	$HAVE_GETTIMEOFDAY
#define HAVE_GETHOSTBYNAME	$HAVE_GETHOSTBYNAME
#define HAVE_UMASK		$HAVE_UMASK
#define HAVE_LCRYPT		$HAVE_LCRYPT

typedef signed $TYPE_INT8 int8;
typedef unsigned $TYPE_INT8 uint8;
typedef signed $TYPE_INT16 int16;
typedef unsigned $TYPE_INT16 uint16;
typedef signed $TYPE_INT32 int32;
typedef unsigned $TYPE_INT32 uint32;
typedef signed $TYPE_INT64 int64;
typedef unsigned $TYPE_INT64 uint64;
_EOT_
    echo "done."

echo2 "Creating Makefile.inc ...                   "
cat >Makefile.inc <<_EOT_
# This file is generated automatically by "configure".  Any changes made
# to it will be erased next time "configure" is run.

CC=$CC
CFLAGS=$CC_FLAGS
LFLAGS=$CC_LFLAGS
LIBS=$CC_LIBS
DEST=$DEST
_EOT_

if [ $CONVERT -eq 1 ] ; then cat <<_EOT_ >>Makefile.inc
CONVERT=$CONVERT
_EOT_
fi

echo "done."

# Save results in cache for next time around.

echo2 "Creating configure.cache ...                "

cat <<EOT >configure.cache
DEST="$DEST"
CONVERT="$CONVERT"
CC="$CC"
CC_FLAGS="$CC_FLAGS"
CC_LFLAGS="$CC_LFLAGS"
CC_LIBS="$CC_LIBS"
TYPE_INT8=$TYPE_INT8
TYPE_INT16=$TYPE_INT16
TYPE_INT32=$TYPE_INT32
TYPE_INT64="$TYPE_INT64"
HAVE_GETTIMEOFDAY=$HAVE_GETTIMEOFDAY
HAVE_LCRYPT=$HAVE_LCRYPT
HAVE_UMASK=$HAVE_UMASK
HAVE_GETHOSTBYNAME=$HAVE_GETHOSTBYNAME
MISSING="$MISSING"
EOT

echo "done."

# Remove our tmp dir.
if [ -d tmp ] ; then
    rm -rf tmp
fi

echo " "
echo "*** Configuration is complete. Please check inc/config.h for any"
echo "*** options you wish to change. Once you are done with config.h,"
echo "*** type 'make' to compile $PACKAGE. If this fails, try 'gmake'."
echo " "
exit 0
