#!/bin/bash
#This library of Shell Accessible Modules is Copyright 1997-2001
#by William Stearns <wstearns@pobox.com>
#
#To include these functions in your shell script, enter the following:
#if [ -f /usr/lib/samlib/samlib ]; then
#	. /usr/lib/samlib/samlib
#else
#	echo "/usr/lib/samlib/samlib is missing - please get it from" >/dev/stderr
#	echo "http://www.pobox.com/~wstearns/" >/dev/stderr
#	echo "Exiting." >/dev/stderr
#	exit 1
#fi
#for ONEFUNC in    list needed functions here   ; do
#	if ! type $ONEFUNC >/dev/null 2>/dev/null ; then
#		echo "Missing $ONEFUNC , please update samlib from" >/dev/stderr
#		echo "http://www.pobox.com/~wstearns/" >/dev/stderr
#		echo "Exiting." >/dev/stderr
#		exit 1
#	fi
#done
#Checks done on the above: 1-3,5-7,9-16
#
#To make them available in your running shell, type:
#. /usr/lib/samlib/samlib

#Checks:
# 1. Sudo/askfirst checked; no root assumptions.
# 2. Standalone - no requirements of pre-existing functions
# 3. Support apps explicitly listed and Prereq'd in spec file
# 4. Regression test function for each function, listed in REGRESSIONTESTS
# 5. Only load tests if regression test requested.
# 6. Conditional functions based on whether support apps available or a fallback needed.
# 7. No assumptions about initialized variables.
# 8. Local variables if possible.
# 9. No modification of global variables.
#10. Hell, not even _use_ of global variables.
#11. No side effects to the system.
#12. Careful use of >/dev/stderr for status/errors.
#13. No assumptions that paths exist.
#14. Use mktemp if available, warn and fallback if not.
#15. Example calls in header.
#16. Quote variables to handle unset/null case.
#17. Debian "must return true" requirement checked.
#99. Header to show inputs, outputs, return codes, exceptions to the above, programs that are known to use this function.

#Programs known to use this library: buildkernel >= 1.04, Mason >= 0.13.9.4, mkrootfs.
#Programs that should: ramenfind, uml loader, freedups, ssh-keyinstall


#Future:
#- don't assume[/usr]/[s]bin in path
#FIXME - resolve SUDO vs PRECOMMAND.
#FIXME - do a requireutil $SUDO when SUDO assigned.
#FIXME - replacement mktemp if the real mktemp isn't on the system.

#Regression test template
#if [ "$DOREGRESSIONTEST" = "YES" ]; then
	#echo -n func...
	#Should return true
	#if !   ; then						error func-tx ; fi
	#Should return false
	#if   ; then						error func-fx ; fi
	#General return values
	#if [ ! `` = "" ]; then					error func-x ; fi
#fi



SAMVER="0.2, 9/16/2001"


if [ "${1}" = "regression-test" ]; then
	DOREGRESSIONTEST=YES
	#Checks done on the following function: 
	error () {
		echo 
		echo Failed test: $*
		if [ -d /usr/src/samlib-work ]; then
			echo Failed test: $* on $SAMVER >>/usr/src/samlib-work/regression-log
		fi
		echo -n -e "\a" >/dev/stderr
		sleep 1
		echo -n -e "\a" >/dev/stderr
		sleep 1
		echo -n -e "\a" >/dev/stderr
		exit 1
	}
fi
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	#Internal check.  If you want to check that the error function actually catches failures, uncomment the following.
	#if ! false ; then									error testfail ; fi
	echo -n samver...
	if [ -z "$SAMVER" ]; then								error samver ; fi
fi


# Near the top of the library as some of the following functions call this
# to register their own needed functions.
#-------------------------------------------------------------------------
# requireutil function, makes sure that the needed external program(s)
# (listed on the command line) is/are in the path and executable.
# Correctly handles the case where the utility is a shell function.
# Example use:
#	requireutil ls || exit 1
#-------------------------------------------------------------------------
#Checks done on the following function: 
requireutil () {
	while [ -n "$1" ]; do
		if ! type -path "$1" >/dev/null 2>/dev/null ; then
			echo Missing utility "$1". Please install it. >/dev/stderr
			return 1	#False, app is not available.
		fi
		shift
	done
	return 0	#True, app is there.
} #End of requireutil
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n requireutil...
	if ! requireutil ls ; then								error requireutil-t1 ; fi
	if requireutil wehwegtgwerbcvhjdsbf 2>/dev/null ; then					error requireutil-f1 ; fi
	#I think only debian includes that one... ;-)
fi


#ZZZZ
if /bin/false ; then	#Under development, hardly even complete.


#-------------------------------------------------------------------------
# mktemp replacement; creates a temporary file.  Used only if the system
# does not have an mktemp program.
#-------------------------------------------------------------------------
if ! type -path mktemp >/dev/null 2>/dev/null ; then
	echo 'Warning!  This system does not have mktemp program.  I will install' >/dev/stderr
	echo 'a replacement, but it is not secure.  Please install the mktemp' >/dev/stderr
	echo 'package.' >/dev/stderr
	#Checks done on the following function: 
	mktemp () {
		if [ $# = 0 ]; then
			echo Too few parameters to mktemp, exiting. >/dev/stderr
			return 1
		fi
		while [ -n "$1" ]; do
			case "$1" in
			-d)
				:
				shift
				;;
			-q)
				:
				shift
				;;
			-u)
				:
				shift
				;;
			*)
				BASEFILE="$1"			
				shift
				;;
			esac
		
		done
		if [ ! -d /tmp ]; then
			echo Missing /tmp directory, please create and restart. Mktemp Exiting. >/dev/stderr
			return 1
		fi
		TEMPFILE=/tmp/file.$$.$RANDOM		#<-- Yes, this is a race condition.
		while [ -e $TEMPFILE ]; do		#
			TEMPFILE=/tmp/file.$$.$RANDOM	#    That's why I suggest they get a real mktemp.
		done					#
		touch $TEMPFILE				#<-- Oh well.
		
		#if some_check_that_a_file_was_actually_created ; then
			echo $TEMPFILE
			return 0
		#else
			#return 1
		#fi
	}
fi


fi


#-------------------------------------------------------------------------
# addline procedure, appends $2 to the end of file $1.
#-------------------------------------------------------------------------
#Params: $1 File that needs the additional line, $2 line to add.
requireutil cat $SUDO grep printf mktemp rm dd touch || exit 1	#umask is a shell builtin.
#Checks done on the following function: 
addline() {
	if [ "$#" != "2" ]; then
		echo Incorrect number of arguments to addline! >/dev/stderr
	else
		#case "$1" in
		#/*)
		#    echo Filename is not relative in addline! >/dev/stderr
		#    ;;
		#*)
		if [ -f "$1" ] && $SUDO cat "$1" | grep -q "^$2\$" ; then
			echo \"$2\" is already in $1 - not adding again. >/dev/stderr
		else
			printf "%-3s%-40s%-50s\n" '+' "$1" "$2"		#Was: echo Adding \"$2\" to $1
			if [ -f $1 ]; then
				OLDUMASK=`umask`
				umask 177
				TMPFILE=`mktemp -q /tmp/addline.XXXXXX`
				if [ $? -ne 0 ]; then
					echo "$0: Can't create temp file, exiting..."
					exit 1
				fi
				#Yes, this is ugly, but _you_ try getting sudo to allow you to append as root as well!
				#$SUDO echo "$2" >>$1	- doesn't work.
				$SUDO cat "$1" >"$TMPFILE"
				echo "$2" | cat "$TMPFILE" - | $SUDO dd of="$1" 2>/dev/null
				$SUDO rm -f "$TMPFILE"
				umask $OLDUMASK
			else
				$SUDO touch "$1"
				echo "$2" | $SUDO dd of="$1" 2>/dev/null
			fi
		fi
		#    ;;
		#esac
	fi
} #End of addline
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n addline...
	REGRESSTESTFILE=`mktemp -q /tmp/$1.XXXXXX`
	if [ $? -ne 0 ]; then
		echo "$0: Can't create regression temp file, exiting..."
		exit 1
	fi
	addline $REGRESSTESTFILE "A line of text" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"A line of text" \
	]; then											error addline-1 ; fi
	addline $REGRESSTESTFILE "A new line of text" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"A line of text
A new line of text" \
	]; then											error addline-2 ; fi
	rm -f $REGRESSTESTFILE
fi


#-------------------------------------------------------------------------
# askYN function, returns true or false depending on user input.
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
askYN () {	#SUDO checked
	TESTYN=""
	while [ "$TESTYN" != 'Y' ] && [ "$TESTYN" != 'N' ] ; do
		echo -n '?' >/dev/stderr
		read TESTYN || :
		case $TESTYN in
		T*|t*|Y*|y*)		TESTYN='Y'	;;
		F*|f*|N*|n*)		TESTYN='N'	;;
		esac
	done

	if [ "$TESTYN" = 'Y' ]; then
		return 0 #True
	else
		return 1 #False
	fi
} #End of askYN
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n askYN...
	if ! echo 'Y' | askYN 2>/dev/null ; then						error askYN-t1 ; fi
	if ! echo 'y' | askYN 2>/dev/null ; then						error askYN-t2 ; fi
	if ! echo 'T' | askYN 2>/dev/null ; then						error askYN-t3 ; fi
	if ! echo 't' | askYN 2>/dev/null ; then						error askYN-t4 ; fi
	if ! echo 'yES' | askYN 2>/dev/null ; then						error askYN-t5 ; fi
	if ! echo 'true' | askYN 2>/dev/null ; then						error askYN-t6 ; fi
	if echo 'N' | askYN 2>/dev/null ; then							error askYN-f1 ; fi
	if echo 'n' | askYN 2>/dev/null ; then							error askYN-f2 ; fi
	if echo 'F' | askYN 2>/dev/null ; then							error askYN-f3 ; fi
	if echo 'f' | askYN 2>/dev/null ; then							error askYN-f4 ; fi
	if echo 'No' | askYN 2>/dev/null ; then							error askYN-f5 ; fi
	if echo 'FALSE' | askYN 2>/dev/null ; then						error askYN-f6 ; fi
fi


#-------------------------------------------------------------------------
# bits2mask function, returns the netmask for the number of bits parameter.
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
bits2mask () {
	case $1 in
	32|*/32)	echo 255.255.255.255	;;
	31|*/31)	echo 255.255.255.254	;;
	30|*/30)	echo 255.255.255.252	;;
	29|*/29)	echo 255.255.255.248	;;
	28|*/28)	echo 255.255.255.240	;;
	27|*/27)	echo 255.255.255.224	;;
	26|*/26)	echo 255.255.255.192	;;
	25|*/25)	echo 255.255.255.128	;;

	24|*/24)	echo 255.255.255.0	;;
	23|*/23)	echo 255.255.254.0	;;
	22|*/22)	echo 255.255.252.0	;;
	21|*/21)	echo 255.255.248.0	;;
	20|*/20)	echo 255.255.240.0	;;
	19|*/19)	echo 255.255.224.0	;;
	18|*/18)	echo 255.255.192.0	;;
	17|*/17)	echo 255.255.128.0	;;

	16|*/16)	echo 255.255.0.0	;;
	15|*/15)	echo 255.254.0.0	;;
	14|*/14)	echo 255.252.0.0	;;
	13|*/13)	echo 255.248.0.0	;;
	12|*/12)	echo 255.240.0.0	;;
	11|*/11)	echo 255.224.0.0	;;
	10|*/10)	echo 255.192.0.0	;;
	9|*/9)		echo 255.128.0.0	;;

	8|*/8)		echo 255.0.0.0		;;
	7|*/7)		echo 254.0.0.0		;;
	6|*/6)		echo 252.0.0.0		;;
	5|*/5)		echo 248.0.0.0		;;
	4|*/4)		echo 240.0.0.0		;;
	3|*/3)		echo 224.0.0.0		;;
	2|*/2)		echo 192.0.0.0		;;
	1|*/1)		echo 128.0.0.0		;;
	0|*/0)		echo 0.0.0.0		;;
	*)		echo 255.255.255.255	;;
	esac
} #End of bits2mask
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n bits2mask...
	#General return values
	if [ ! `bits2mask` = "255.255.255.255" ]; then						error bits2mask-1 ; fi
	if [ ! `bits2mask 5` = "248.0.0.0" ]; then						error bits2mask-2 ; fi
	if [ ! `bits2mask 1/30` = "255.255.255.252" ]; then					error bits2mask-3 ; fi
fi


#-------------------------------------------------------------------------
# broadcastof function, returns the broadcast of the given ip and netmask.
#-------------------------------------------------------------------------
requireutil bits2mask || exit 1
#Checks done on the following function: 
broadcastof () {
#The broadcast is (ip bitwise-or (255.255.255.255-netmask))
	CKPTBROADCASTOF=" broadcastof: Start $1 mask $2" ; #ckpt $CKPTBROADCASTOF

	case $2 in
	32|255.255.255.255)	echo $1									;;
	0|0.0.0.0)			echo 255.255.255.255					;;
	*)
		SPLITIP=$1
		I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O4=$SPLITIP
		case $2 in
		[0-9]|[1-2][0-9]|3[0-2])	SPLITIP=`bits2mask $2`			;;
		*)							SPLITIP=$2						;;
		esac
		I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O4=$SPLITIP
	
		echo $[ $I1O1 | (255-$I2O1) ].$[ $I1O2 | (255-$I2O2) ].$[ $I1O3 | (255-$I2O3) ].$[ $I1O4 | (255-$I2O4) ]
																;;
	esac

	CKPTBROADCASTOF=""
} #End of broadcastof
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n broadcastof...
	if [ ! `broadcastof 0.0.0.0 0.0.0.0` = "255.255.255.255" ]; then			error broadcastof-1 ; fi
	if [ ! `broadcastof 1.2.3.4 255.255.255.0` = "1.2.3.255" ]; then			error broadcastof-2 ; fi
	if [ ! `broadcastof 15.1.2.3 255.0.0.0` = "15.255.255.255" ]; then			error broadcastof-3 ; fi
	if [ ! `broadcastof 1.2.3.4 128.0.0.0` = "127.255.255.255" ]; then			error broadcastof-4 ; fi
fi


#-------------------------------------------------------------------------
# delline procedure, removes all lines matching $2 from the given file $1.
#-------------------------------------------------------------------------
requireutil cat $SUDO grep mktemp dd printf rm || exit 1
#Checks done on the following function: 
delline() {
#Params: $1 File that needs the line removed, $2 line to remove (may be a partial line).
#Example: delline somefile '.*'		#Remove all lines, essentially ">somefile" but using sudo.
	if [ "$#" != "2" ]; then
		echo Incorrect number of arguments to delline! >/dev/stderr
	else
		#case "$1" in
		#/*)
		#    echo Filename is not relative in delline! >/dev/stderr
		#    ;;
		#*)
		if [ ! -f "$1" ]; then
			echo "$1" doesn\'t exist, can\'t remove \"$2\". >/dev/stderr
#FIXME - does this allow a partial line?
		elif $SUDO cat "$1" | grep -q "$2" ; then
			OLDUMASK=`umask`
			umask 177
			TMPFILE=`mktemp -q /tmp/delline.XXXXXX`
			if [ $? -ne 0 ]; then
				echo "$0: Can't create temp file, exiting..."
				exit 1
			fi
			$SUDO cat "$1" >"$TMPFILE"
			cat "$TMPFILE" | grep -v "$2" | $SUDO dd of="$1" 2>/dev/null
			printf "%1s%-2s%-40s%-50s\n" '-' "$[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ]" "$1" "$2"
			#Was: echo -n "Removing \"$2\" from $1; " ; echo $[ `$SUDO cat "$TMPFILE" | wc -l` - `$SUDO cat "$1" | wc -l` ] lines removed.
			$SUDO rm -f "$TMPFILE"
			umask $OLDUMASK
		else
			echo \"$2\" is not in "$1" - not removing. >/dev/stderr
		fi
		#    ;;
		#esac
	fi
}
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n delline...
	REGRESSTESTFILE=`mktemp -q /tmp/$1.XXXXXX`
	if [ $? -ne 0 ]; then
		echo "$0: Can't create regression temp file, exiting..."
		exit 1
	fi
	echo Line 1 >$REGRESSTESTFILE
	echo Line 2 >>$REGRESSTESTFILE
	echo Line 3 >>$REGRESSTESTFILE
	echo Line 4 >>$REGRESSTESTFILE
	echo Line 5 >>$REGRESSTESTFILE
	delline $REGRESSTESTFILE "Line 4" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line 2
Line 3
Line 5" \
	]; then											error delline-1 ; fi
	delline $REGRESSTESTFILE "Isnt in the file" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line 2
Line 3
Line 5" \
	]; then											error delline-2 ; fi
	delline $REGRESSTESTFILE "3" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line 2
Line 5" \
	]; then											error delline-3 ; fi
	delline $REGRESSTESTFILE "Line 1" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 2
Line 5" \
	]; then											error delline-4 ; fi
	delline $REGRESSTESTFILE "Line 5" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 2" \
	]; then											error delline-5 ; fi
	rm -f $REGRESSTESTFILE
fi


#-------------------------------------------------------------------------
# ipeq function, returns true/false: ip addresses are equal? 
#-------------------------------------------------------------------------
#Not currently used...
#No external apps needed.
#Checks done on the following function: 
ipeq () {	#SUDO checked
	if [ "$1" = "$2" ]; then
		return 0	#True
	else
		SPLITIP=$1
		I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O4=$SPLITIP
		SPLITIP=$2
		I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O4=$SPLITIP
	
		if [ $I1O1 -eq $I2O1 ] && [ $I1O2 -eq $I2O2 ] && [ $I1O3 -eq $I2O3 ] && [ $I1O4 -eq $I2O4 ]; then
			return 0 #True
		else
			return 1 #False
		fi
	fi
} #End of ipeq
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n ipeq...
	if ! ipeq 1.1.1.1 1.1.1.1 ; then							error ipeq-t1 ; fi
	if ! ipeq 255.255.255.255 255.255.255.255 ; then					error ipeq-t2 ; fi
	if ipeq 1.1.1.1 1.2.3.4 ; then								error ipeq-f1 ; fi
fi


#-------------------------------------------------------------------------
# iple function, returns true (0) if first IP <= second IP, else false(1)
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
iple () {	#SUDO checked
#if iple 128.2.3.4 127.0.0.1 ; then echo less than or eq >/dev/stderr ; else echo gt >/dev/stderr ; fi
	if [ "$1" = "$2" ]; then
		CKPTIPLE="" ; return 0	#True
	else
		CKPTIPLE=" iple: start, addresses $1 and $2" ; #ckpt $CKPTIPLE

		SPLITIP1=$1 ;			I1O1=${SPLITIP1%%.*}
		SPLITIP2=$2 ;			I2O1=${SPLITIP2%%.*}
		  if [ $I1O1 -lt $I2O1 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O2=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O2=${SPLITIP2%%.*}
		  if [ $I1O2 -lt $I2O2 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O3=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O3=${SPLITIP2%%.*}
		  if [ $I1O3 -lt $I2O3 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O4=$SPLITIP1
		SPLITIP2=${SPLITIP2#*.} ;	I2O4=$SPLITIP2
		  if [ $I1O4 -lt $I2O4 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLE="" ; return 1
		else				CKPTIPLE="" ; return 0
		fi
	fi
} #End of iple
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n iple...
	if ! iple 12.13.14.15 12.13.14.15 ; then						error iple-t1 ; fi
	if ! iple 12.13.14.15 12.13.14.16 ; then						error iple-t2 ; fi
	if ! iple 0.0.0.0 12.13.14.15 ; then							error iple-t3 ; fi
	if ! iple 0.0.0.0 255.255.255.255 ; then						error iple-t4 ; fi
	if ! iple 12.11.11.11 12.44.45.46 ; then						error iple-t5 ; fi
	if ! iple 12.11.11.11 12.11.45.46 ; then						error iple-t6 ; fi
	if ! iple 12.11.11.11 12.11.11.46 ; then						error iple-t7 ; fi
	if iple 12.13.14.16 12.13.14.15 ; then							error iple-f1 ; fi
	if iple 12.13.14.15 0.0.0.0 ; then							error iple-f2 ; fi
	if iple 255.255.255.255 0.0.0.0 ; then							error iple-f3 ; fi
	if iple 12.44.45.46 12.11.11.11 ; then							error iple-f4 ; fi
fi


#-------------------------------------------------------------------------
# iplt function, returns true (0) if first IP < second IP, else false(1)
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
iplt () {	#SUDO checked
#if iplt 128.2.3.4 127.0.0.1 ; then echo less than >/dev/stderr ; else echo ge >/dev/stderr ; fi
#As a speedup, only come up with the individual numbers as they are needed.
	if [ "$1" = "$2" ]; then
		CKPTIPLT="" ; return 1	#False
	else
		CKPTIPLT=" iplt: start, addresses $1 and $2" ; #ckpt $CKPTIPLT

		SPLITIP1=$1 ;			I1O1=${SPLITIP1%%.*}
		SPLITIP2=$2 ;			I2O1=${SPLITIP2%%.*}
		  if [ $I1O1 -lt $I2O1 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLT="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O2=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O2=${SPLITIP2%%.*}
		  if [ $I1O2 -lt $I2O2 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLT="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O3=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O3=${SPLITIP2%%.*}
		  if [ $I1O3 -lt $I2O3 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLT="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O4=$SPLITIP1
		SPLITIP2=${SPLITIP2#*.} ;	I2O4=$SPLITIP2
		  if [ $I1O4 -lt $I2O4 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLT="" ; return 1
		else				CKPTIPLT="" ; return 1
		fi
	fi
} #End of iplt
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n iplt...
	if ! iplt 12.13.14.15 12.13.14.16 ; then						error iplt-t1 ; fi
	if ! iplt 0.0.0.0 12.13.14.15 ; then							error iplt-t2 ; fi
	if ! iplt 0.0.0.0 255.255.255.255 ; then						error iplt-t3 ; fi
	if ! iplt 12.11.11.11 12.44.45.46 ; then						error iplt-t4 ; fi
	if iplt 12.13.14.16 12.13.14.15 ; then							error iplt-f1 ; fi
	if iplt 12.13.14.15 0.0.0.0 ; then							error iplt-f2 ; fi
	if iplt 255.255.255.255 0.0.0.0 ; then							error iplt-f3 ; fi
	if iplt 12.44.45.46 12.11.11.11 ; then							error iplt-f4 ; fi
	if iplt 12.44.45.46 12.44.45.46 ; then							error iplt-f5 ; fi
fi


#-------------------------------------------------------------------------
# ipof function, returns the ip address of the given interface, or '' if none assigned.
#-------------------------------------------------------------------------
requireutil ifconfig awk || exit 1
#Checks done on the following function: 
ipof () {	#SUDO checked
    ifconfig $1 2>/dev/null | awk '/inet addr/{print substr($2,6)}'
} #End of ipof
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n ipof...
	if [ ! "`ipof lo`" = "127.0.0.1" ]; then						error ipof-1 ; fi
	if [ ! "`ipof qeqeqeqeqeqeqeqe`" = "" ]; then						error ipof-2 ; fi
fi


#-------------------------------------------------------------------------
# isdigits function, returns true (0) if parameter is numeric and between 0 and 99999, else false(1)
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
isdigits () {	#SUDO checked
	case $1 in
	[0-9])						return 0						;;
	[0-9][0-9])					return 0						;;
	[0-9][0-9][0-9])			return 0						;;
	[0-9][0-9][0-9][0-9])		return 0						;;
	[0-9][0-9][0-9][0-9][0-9])	return 0						;;
	*)							return 1						;;
	esac
}
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n isdigits...
	if ! isdigits 0 ; then									error isdigits-t1 ; fi
	if ! isdigits 00 ; then									error isdigits-t2 ; fi
	if ! isdigits 101 ; then								error isdigits-t3 ; fi
	if ! isdigits 4987 ; then								error isdigits-t4 ; fi
	if ! isdigits 44567 ; then								error isdigits-t5 ; fi
	if ! isdigits 00000 ; then								error isdigits-t6 ; fi
	if ! isdigits 99999 ; then								error isdigits-t7 ; fi
	if isdigits '' ; then									error isdigits-f1 ; fi
	if isdigits a ; then									error isdigits-f2 ; fi
	if isdigits a0a ; then									error isdigits-f3 ; fi
	if isdigits 00B ; then									error isdigits-f4 ; fi
	if isdigits 123456 ; then								error isdigits-f5 ; fi
	if isdigits "" ; then									error isdigits-f6 ; fi
fi


#-------------------------------------------------------------------------
# isnumericip function, returns true (0) if IP is a numeric IP address, else false(1)
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
isnumericip () {	#SUDO checked
	CKPTISNUMERICIP=" isnumericip: start $1" ; #ckpt $CKPTISNUMERICIP

	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP

	case $I1O1 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:					;;
	*)								CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O2 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:					;;
	*)								CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O3 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:					;;
	*)								CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O4 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:					;;
	*)								CKPTISNUMERICIP="" ; return 1	;;
	esac

	CKPTISNUMERICIP="" ; return 0
} #End of isnumericip
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n isnumericip...
	if ! isnumericip 1.1.1.1 ; then								error isnumericip-t1 ; fi
	if ! isnumericip 0.0.0.0 ; then								error isnumericip-t2 ; fi
	if ! isnumericip 255.255.255.255 ; then							error isnumericip-t3 ; fi
	if ! isnumericip 1.2.3.4 ; then								error isnumericip-t4 ; fi
	if ! isnumericip 127.0.0.1 ; then							error isnumericip-t5 ; fi
	if ! isnumericip 192.168.234.243 ; then							error isnumericip-t6 ; fi
	if isnumericip 1.1.1. ; then								error isnumericip-f1 ; fi
	if isnumericip a ; then									error isnumericip-f2 ; fi
	if isnumericip 1..1.1.1 ; then								error isnumericip-f3 ; fi
	if isnumericip .1.1.1.1 ; then								error isnumericip-f4 ; fi
	if isnumericip 1.1.1.1.1 ; then								error isnumericip-f5 ; fi
	if isnumericip 256.1.1.1 ; then								error isnumericip-f6 ; fi
	if isnumericip 1.256.1.1 ; then								error isnumericip-f7 ; fi
	if isnumericip 1.1.256.1 ; then								error isnumericip-f8 ; fi
	if isnumericip 1.1.1.256 ; then								error isnumericip-f9 ; fi
	if isnumericip -1.5.6.7 ; then								error isnumericip-f10 ; fi
	if isnumericip 12.13.14.15a ; then							error isnumericip-f11 ; fi
	if isnumericip a.b.c.d ; then								error isnumericip-f12 ; fi
	if isnumericip ... ; then								error isnumericip-f13 ; fi
fi


#-------------------------------------------------------------------------
# mask2bits function, returns the number of bits in the netmask parameter.
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
mask2bits () {	#SUDO checked
	case $1 in
	255.255.255.255)	echo 32									;;
	255.255.255.254)	echo 31									;;
	255.255.255.252)	echo 30									;;
	255.255.255.248)	echo 29									;;
	255.255.255.240)	echo 28									;;
	255.255.255.224)	echo 27									;;
	255.255.255.192)	echo 26									;;
	255.255.255.128)	echo 25									;;
	255.255.255.0)		echo 24									;;
	255.255.254.0)		echo 23									;;
	255.255.252.0)		echo 22									;;
	255.255.248.0)		echo 21									;;
	255.255.240.0)		echo 20									;;
	255.255.224.0)		echo 19									;;
	255.255.192.0)		echo 18									;;
	255.255.128.0)		echo 17									;;
	255.255.0.0)		echo 16									;;
	255.254.0.0)		echo 15									;;
	255.252.0.0)		echo 14									;;
	255.248.0.0)		echo 13									;;
	255.240.0.0)		echo 12									;;
	255.224.0.0)		echo 11									;;
	255.192.0.0)		echo 10									;;
	255.128.0.0)		echo 9									;;
	255.0.0.0)		echo 8									;;
	254.0.0.0)		echo 7									;;
	252.0.0.0)		echo 6									;;
	248.0.0.0)		echo 5									;;
	240.0.0.0)		echo 4									;;
	224.0.0.0)		echo 3									;;
	192.0.0.0)		echo 2									;;
	128.0.0.0)		echo 1									;;
	0.0.0.0)		echo 0									;;
	*)			echo 32									;;
	esac
} #End of mask2bits
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n mask2bits...
	if [ ! `mask2bits 255.255.255.255` = "32" ]; then					error mask2bits-1 ; fi
	if [ ! `mask2bits 255.255.255.254` = "31" ]; then					error mask2bits-2 ; fi
	if [ ! `mask2bits 255.255.255.252` = "30" ]; then					error mask2bits-3 ; fi
	if [ ! `mask2bits 255.255.255.248` = "29" ]; then					error mask2bits-4 ; fi
	if [ ! `mask2bits 128.0.0.0` = "1" ]; then						error mask2bits-5 ; fi
	if [ ! `mask2bits 0.0.0.0` = "0" ]; then						error mask2bits-6 ; fi
fi


#-------------------------------------------------------------------------
# mask2cisco function, returns the cisco "reverse netmask" of the netmask parameter.
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
mask2cisco () {	#SUDO checked
#This could be done in fewer lines by subtracting each octet from 255.
#I'm trying to avoid forking as it hurts performance.
	case $1 in
	32|255.255.255.255)	echo 0.0.0.0							;;
	31|255.255.255.254)	echo 0.0.0.1							;;
	30|255.255.255.252)	echo 0.0.0.3							;;
	29|255.255.255.248)	echo 0.0.0.7							;;
	28|255.255.255.240)	echo 0.0.0.15							;;
	27|255.255.255.224)	echo 0.0.0.31							;;
	26|255.255.255.192)	echo 0.0.0.63							;;
	25|255.255.255.128)	echo 0.0.0.127							;;
	24|255.255.255.0)	echo 0.0.0.255							;;
	23|255.255.254.0)	echo 0.0.1.255							;;
	22|255.255.252.0)	echo 0.0.3.255							;;
	21|255.255.248.0)	echo 0.0.7.255							;;
	20|255.255.240.0)	echo 0.0.15.255							;;
	19|255.255.224.0)	echo 0.0.31.255							;;
	18|255.255.192.0)	echo 0.0.63.255							;;
	17|255.255.128.0)	echo 0.0.127.255						;;
	16|255.255.0.0)		echo 0.0.255.255						;;
	15|255.254.0.0)		echo 0.1.255.255						;;
	14|255.252.0.0)		echo 0.3.255.255						;;
	13|255.248.0.0)		echo 0.7.255.255						;;
	12|255.240.0.0)		echo 0.15.255.255						;;
	11|255.224.0.0)		echo 0.31.255.255						;;
	10|255.192.0.0)		echo 0.63.255.255						;;
	9|255.128.0.0)		echo 0.127.255.255						;;
	8|255.0.0.0)		echo 0.255.255.255						;;
	7|254.0.0.0)		echo 1.255.255.255						;;
	6|252.0.0.0)		echo 3.255.255.255						;;
	5|248.0.0.0)		echo 7.255.255.255						;;
	4|240.0.0.0)		echo 15.255.255.255						;;
	3|224.0.0.0)		echo 31.255.255.255						;;
	2|192.0.0.0)		echo 63.255.255.255						;;
	1|128.0.0.0)		echo 127.255.255.255						;;
	0|0.0.0.0)		echo 255.255.255.255						;;
	*)			echo 0.0.0.0							;;
	esac
} #End of mask2cisco
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n mask2cisco...
	if [ ! `mask2cisco 255.255.255.128` = "0.0.0.127" ]; then				error mask2cisco-1 ; fi
	if [ ! `mask2cisco 255.255.192.0` = "0.0.63.255" ]; then				error mask2cisco-2 ; fi
	if [ ! `mask2cisco 22` = "0.0.3.255" ]; then						error mask2cisco-3 ; fi
fi


#-------------------------------------------------------------------------
# max function, Returns the largest of the CLP's, or 0 if none.
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
max () {
    if [ $# -eq 0 ]; then
	echo 0
    else
	MAX=$1
	shift
	while [ -n "$1" ]; do
	    if [ $[ $1 ] -gt $MAX ]; then
		MAX=$[ $1 ]
	    fi
	    shift
	done
	echo $MAX
    fi
} #End of max
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n max...
	#General return values
	if [ ! `max` = "0" ]; then								error max-1 ; fi
	if [ ! `max 1` = "1" ]; then								error max-2 ; fi
	if [ ! `max 2 5` = "5" ]; then								error max-3 ; fi
	if [ ! `max -2 -4` = "-2" ]; then							error max-4 ; fi
	if [ ! `max -2 -4 13 -10` = "13" ]; then						error max-5 ; fi
	if [ ! `max 1 1 1 1 1` = "1" ]; then							error max-6 ; fi
fi


#-------------------------------------------------------------------------
# networkof function, returns the network of the given ip and netmask.
#-------------------------------------------------------------------------
requireutil bits2mask || exit 1
#Checks done on the following function: 
networkof () {
#Basically, the network is (ip bitwise-and netmask)
	CKPTNETWORKOF=" networkof: Start $1 mask $2" ; #ckpt $CKPTNETWORKOF

	case $2 in
	32|255.255.255.255)	echo $1									;;
	0|0.0.0.0)			echo 0.0.0.0							;;
	*)
		SPLITIP=$1
		I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O4=$SPLITIP
		case $2 in
		[0-9]|[1-2][0-9]|3[0-2])	SPLITIP=`bits2mask $2`			;;
		*)							SPLITIP=$2						;;
		esac
		I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I2O4=$SPLITIP

		echo $[ $I1O1 & $I2O1 ].$[ $I1O2 & $I2O2 ].$[ $I1O3 & $I2O3 ].$[ $I1O4 & $I2O4 ]
																;;
	esac
	CKPTNETWORKOF=""
} #End of networkof
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n networkof...
	if [ ! `networkof 0.0.0.0 0.0.0.0` = "0.0.0.0" ]; then					error networkof-1 ; fi
	if [ ! `networkof 1.2.3.4 255.255.255.0` = "1.2.3.0" ]; then				error networkof-2 ; fi
	if [ ! `networkof 15.1.2.3 255.0.0.0` = "15.0.0.0" ]; then				error networkof-3 ; fi
	if [ ! `networkof 1.2.3.4 128.0.0.0` = "0.0.0.0" ]; then				error networkof-4 ; fi
	if [ ! `networkof 0.0.0.0 0` = "0.0.0.0" ]; then					error networkof-5 ; fi
	if [ ! `networkof 1.2.3.4 24` = "1.2.3.0" ]; then					error networkof-6 ; fi
	if [ ! `networkof 15.1.2.3 8` = "15.0.0.0" ]; then					error networkof-7 ; fi
	if [ ! `networkof 1.2.3.4 1` = "0.0.0.0" ]; then					error networkof-8 ; fi
	if [ ! `networkof 1.2.3.4 0.0.0.0` = "0.0.0.0" ]; then					error networkof-9 ; fi
fi

#-------------------------------------------------------------------------
# networksoverlap function, returns true (0) if the two param networks overlap, false otherwise.
#-------------------------------------------------------------------------
requireutil networkof broadcastof iple || exit 1
#Checks done on the following function: 
networksoverlap () {	#SUDO checked
	#FIXME - handle, or get networkof/broadcastof to handle, '0' as the network
	N1NET=`networkof ${1%%/*} ${1##*/}` ;	N1BROAD=`broadcastof ${1%%/*} ${1##*/}`
	N2NET=`networkof ${2%%/*} ${2##*/}` ;	N2BROAD=`broadcastof ${2%%/*} ${2##*/}`

	  if iple $N2NET $N1NET &&	iple $N1NET $N2BROAD ; then	return 0	#N1NET inside N2?
	elif iple $N2NET $N1BROAD &&	iple $N1BROAD $N2BROAD ; then	return 0	#N1BROAD inside N2?
	elif iple $N1NET $N2NET &&	iple $N2NET $N1BROAD ; then	return 0	#N2NET inside N1?
	elif iple $N1NET $N2BROAD &&	iple $N2BROAD $N1BROAD ; then	return 0	#N2BROAD inside N1?
	fi
	return 1	#False
} #End of networksoverlap
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n networksoverlap...
	if ! networksoverlap 127.0.0.0/8 127.0.0.0/16 ; then					error networksoverlap-t1 ; fi
	if ! networksoverlap 192.168.1.0/24 192.168.1.252/30 ; then				error networksoverlap-t2 ; fi
	if ! networksoverlap 12.13.14.0/24 0.0.0.0/0; then					error networksoverlap-t3 ; fi
	if ! networksoverlap 0.0.0.0/0 0.0.0.0/0 ; then						error networksoverlap-t4 ; fi
	if networksoverlap 1.2.3.0/24 5.6.7.0/24 ; then						error networksoverlap-f1 ; fi
	if networksoverlap 0.0.0.0/1 128.0.0.0/1 ; then						error networksoverlap-f2 ; fi
	if networksoverlap 1.2.3.248/30 1.2.3.252/30 ; then					error networksoverlap-f3 ; fi
	if networksoverlap 1.2.3.0/24 1.2.4.0/24 ; then						error networksoverlap-f4 ; fi
fi


#Out of alphabetical order because it depends on networkof.  While not a problem
#for simply placing the functions in memory, it makes a difference for this 
#approach of calling the regression tests right after the function.
#-------------------------------------------------------------------------
# encompassingnetworkof function, returns the smallest network that includes
# all of the given ip's.  There must be at least one parameter.
# Please hand in only straight IP's; to include a network in the calculation,
# hand in both: `networkof $NET $NETMASK` `broadcastof $NET $NETMASK`
#-------------------------------------------------------------------------
requireutil iplt bits2mask networkof broadcastof || exit 1
#Checks done on the following function: 
encompassingnetworkof () {	#SUDO checked
	CKPTENCOMPASSINGNETWORKOF=" encompassingnetworkof: Start, ips: $*" ; #ckpt $CKPTENCOMPASSINGNETWORKOF

	case $# in
	0)	:														;;
	1)	echo "$1/32"											;;
	*)
		MINIP=$1	; MAXIP=$1
		shift
		for ONEIP in $* ; do
			if iplt $ONEIP $MINIP ; then MINIP=$ONEIP ; fi
			if iplt $MAXIP $ONEIP ; then MAXIP=$ONEIP ; fi
		done

		SPLITIP=$MINIP ;			MINO1=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MINO2=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MINO3=${SPLITIP%%.*}
		#SPLITIP=${SPLITIP#*.} ;	MINO4=$SPLITIP			#We don't need the MIN04 and MAX04.
		SPLITIP=$MAXIP ;			MAXO1=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MAXO2=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MAXO3=${SPLITIP%%.*}
		#SPLITIP=${SPLITIP#*.} ;	MAXO4=$SPLITIP

		#Find the _starting_ _point_ for the search.
		# - if the first octets are different, start at /8.
		# - if the second octets are different, start at /16.
		# - if the third octets are different, start at /24.
		# - else start at /32.
		#This relatively simple optimization sped up this function by a theoretical factor of 4 
		#and a timed factor of 10 on one example.  *smile*
		#(BTW - It would appear we could start the search at 7, 15, or 23, but the result from 
		#encompassingnetworkof 10.1.2.3 11.12.13.14 10.2.3.4  comes back as 8.0.0.0/6: wrong.
		  if [ $MINO1 -ne $MAXO1 ]; then		ENONUMBITS=8 ;	ENONETMASK=255.0.0.0
		elif [ $MINO2 -ne $MAXO2 ]; then		ENONUMBITS=16 ;	ENONETMASK=255.255.0.0
		elif [ $MINO3 -ne $MAXO3 ]; then		ENONUMBITS=24 ;	ENONETMASK=255.255.255.0
		else						ENONUMBITS=32 ;	ENONETMASK=255.255.255.255 ; fi
		ENONETWORK=$MINIP
		ENOBROADCAST=$MINIP

		#Keep expanding the network until it includes MAXIP.  This takes almost all of the time.
		while [ $ENONUMBITS -gt 0 ] && iplt $ENOBROADCAST $MAXIP ; do
			ENONUMBITS=$[ $ENONUMBITS - 1 ]
			ENONETMASK=`bits2mask $ENONUMBITS`
			ENONETWORK=`networkof $MINIP $ENONETMASK`
			ENOBROADCAST=`broadcastof $MINIP $ENONETMASK`
		done
		if [ "$ENONETWORK/$ENONUMBITS" = "0.0.0.0/0" ]; then ENONETWORK="0" ; fi
		echo "$ENONETWORK/$ENONUMBITS"
																;;
	esac
	CKPTENCOMPASSINGNETWORKOF=""
} #End of encompassingnetworkof
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n encompassingnetworkof...
	if [ ! `encompassingnetworkof 1.2.3.1 1.2.3.1` = "1.2.3.1/32" ]; then			error encompassingnetworkof-1 ; fi
	if [ ! `encompassingnetworkof 1.2.3.2 1.2.3.3` = "1.2.3.2/31" ]; then			error encompassingnetworkof-2 ; fi
	if [ ! `encompassingnetworkof 1.2.3.1 1.2.3.3` = "1.2.3.0/30" ]; then			error encompassingnetworkof-3 ; fi
	if [ ! `encompassingnetworkof 1.2.3.0 1.2.3.255` = "1.2.3.0/24" ]; then			error encompassingnetworkof-4 ; fi
	if [ ! `encompassingnetworkof 0.0.0.0 255.255.255.255` = "0/0" ]; then			error encompassingnetworkof-5 ; fi
	if [ ! `encompassingnetworkof 127.255.255.255 128.0.0.0` = "0/0" ]; then		error encompassingnetworkof-6 ; fi
	if [ ! `encompassingnetworkof 172.16.0.1 172.16.5.5` = "172.16.0.0/21" ]; then		error encompassingnetworkof-7 ; fi
	if [ ! `encompassingnetworkof 206.231.24.3 206.231.24.254 209.91.2.2 209.91.2.253 209.91.28.2 209.91.28.252 209.91.3.1 209.91.3.254 209.91.32.54 209.91.32.72` = "192.0.0.0/3" ]; then	error encompassingnetworkof-8 ; fi
	if [ ! `encompassingnetworkof 10.1.2.3 9.1.2.3` = "8.0.0.0/6" ]; then			error encompassingnetworkof-9 ; fi
	if [ ! `encompassingnetworkof 10.1.2.3 10.255.1.1` = "10.0.0.0/8" ]; then		error encompassingnetworkof-10 ; fi
	if [ ! `encompassingnetworkof 10.1.2.3 11.12.13.14 10.2.3.4` = "10.0.0.0/7" ]; then	error encompassingnetworkof-11 ; fi
	if [ ! `encompassingnetworkof 14.12.1.2 14.12.129.0` = "14.12.0.0/16" ]; then		error encompassingnetworkof-12 ; fi
	if [ ! `encompassingnetworkof 14.13.1.1 14.12.255.255` = "14.12.0.0/15" ]; then		error encompassingnetworkof-13 ; fi
fi


#-------------------------------------------------------------------------
# seqfunc function, creates a sequence of integers from $1 to $2
# Integers only!
#-------------------------------------------------------------------------
#No external apps needed.
#Checks done on the following function: 
seqfunc () {	#SUDO checked
	unset SEQSTART SEQSTOP SEQCOUNT || :
	case $# in
	0)	:														;;
	1)	SEQSTART=1 ; SEQSTOP=$[ $1 ]							;;
	*)	SEQSTART=$[ $1 ] ; SEQSTOP=$[ $2 ]						;;
	esac
	if [ -n "$SEQSTART" ]; then
		if [ $SEQSTART -eq $SEQSTOP ]; then
			echo $SEQSTART
		elif [ $SEQSTART -lt $SEQSTOP ]; then
			SEQCOUNT=$SEQSTART
			while [ $SEQCOUNT -le $SEQSTOP ]; do
				echo $SEQCOUNT
				SEQCOUNT=$[ $SEQCOUNT + 1 ]
			done
		else #$1 > $2
			SEQCOUNT=$SEQSTART
			while [ $SEQCOUNT -ge $SEQSTOP ]; do
				echo $SEQCOUNT
				SEQCOUNT=$[ $SEQCOUNT - 1 ]
			done
		fi
	fi
} #End of seqfunc
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n seqfunc...
	if [ ! "`seqfunc 1`" = "1" ]; then							error seqfunc-1 ; fi
	if [ ! "`seqfunc 5`" = "1
2
3
4
5" \
	]; then											error seqfunc-2 ; fi
	if [ ! "`seqfunc -5`" = "1
0
-1
-2
-3
-4
-5" \
	]; then											error seqfunc-3 ; fi
	if [ ! "`seqfunc 1 5`" = "1
2
3
4
5" \
	]; then											error seqfunc-4 ; fi
	if [ ! "`seqfunc 5 5`" = "5" ]; then							error seqfunc-5 ; fi
	if [ ! "`seqfunc 2 -2`" = "2
1
0
-1
-2" \
	]; then											error seqfunc-6 ; fi
	if [ ! "`seqfunc -1 -1`" = "-1" ]; then							error seqfunc-7 ; fi
	if [ ! "`seqfunc`" = "" ]; then								error seqfunc-8 ; fi


fi


#-------------------------------------------------------------------------
# substline procedure, replaces $2 with $3 in the given file $1
#-------------------------------------------------------------------------
#Params: $1 File that needs the additional line, $2 string to look for, $3 string with which it should be replaced.
#Example:
#substline somefile     "\(^[^#].*\)"   "#\1"
#Translation: add a # in front of all lines that don't have one.
requireutil $SUDO touch cat grep printf umask mktemp sed dd rm || exit 1
#Checks done on the following function: 
substline() {
	if [ "$#" != "3" ]; then
		echo Incorrect number of arguments to substline! >/dev/stderr
	else
		#case "$1" in
		#/*)
		#    echo Filename is not relative in substline! >/dev/stderr
		#    ;;
		#*)
		if [ ! -f "$1" ]; then
			$SUDO touch "$1"
		fi
		if $SUDO cat "$1" | grep -q "$2" ; then
			printf "%-3s%-40s%-50s\n" '-/+' "$1" "$2 -> $3"	#Was: echo Replacing \"$2\" with \"$3\" in $1
			OLDUMASK=`umask`
			umask 177
			TMPFILE=`mktemp -q /tmp/substline.XXXXXX`
			if [ $? -ne 0 ]; then
				echo "$0: Can't create temp file, exiting..."
				exit 1
			fi
			$SUDO cat "$1" >"$TMPFILE"
			cat "$TMPFILE" | sed -e "s@$2@$3@g" | $SUDO dd of="$1" 2>/dev/null
			$SUDO rm -f "$TMPFILE"
			umask $OLDUMASK
		fi
		#    ;;
		#esac
	fi
}
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n substline...
	REGRESSTESTFILE=`mktemp -q /tmp/$1.XXXXXX`
	if [ $? -ne 0 ]; then
		echo "$0: Can't create regression temp file, exiting..."
		exit 1
	fi
	echo Line 1 >$REGRESSTESTFILE
	echo Line 2 >>$REGRESSTESTFILE
	echo Line 3 >>$REGRESSTESTFILE
	echo Line 4 >>$REGRESSTESTFILE
	echo Line 5 >>$REGRESSTESTFILE
	substline $REGRESSTESTFILE "2" "goobers" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line goobers
Line 3
Line 4
Line 5" \
	]; then											error substline-1 ; fi
	substline $REGRESSTESTFILE "Isnt in the file" "ggg" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line goobers
Line 3
Line 4
Line 5" \
	]; then											error substline-2 ; fi
	substline $REGRESSTESTFILE "Line 3" "replacement line" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"Line 1
Line goobers
replacement line
Line 4
Line 5" \
	]; then											error substline-3 ; fi
	substline $REGRESSTESTFILE "Line 1" "new line 1">/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"new line 1
Line goobers
replacement line
Line 4
Line 5" \
	]; then											error substline-4 ; fi
	substline $REGRESSTESTFILE "Line " "circle " >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"new line 1
circle goobers
replacement line
circle 4
circle 5" \
	]; then											error substline-5 ; fi
	substline $REGRESSTESTFILE "e" "qq" >/dev/null 2>/dev/null
	if [ ! "`cat $REGRESSTESTFILE`" = \
"nqqw linqq 1
circlqq goobqqrs
rqqplacqqmqqnt linqq
circlqq 4
circlqq 5" \
	]; then											error substline-6 ; fi
	rm -f $REGRESSTESTFILE
fi




#-------------------------------------------------------------------------
# wrap function, which displays the words on the command line, wrapped
# at LINELENGTH characters.
#-------------------------------------------------------------------------
#The linelength must be larger than the longest word in the string.
#LINELENGTH is the number of displayed characters.
#This should handle command line parameters or stdin.
#If WRAPHEADER is set, its value is placed at the head of each line.
#Uses $ENH (=-e) from calling app.
#No external apps needed.  Even if sed and wc missing, we have a less elegant fallback.
if type -path sed >/dev/null 2>/dev/null && type -path wc >/dev/null 2>/dev/null ; then
	#Checks done on the following function: 1
	wrap () {
		if [ -n "$LINELENGTH" ]; then
			LINELENGTH_INT=$[ $LINELENGTH - `echo -n "$WRAPHEADER" | wc -c` ]
		else
			LINELENGTH_INT=$[ 72 - `echo -n "$WRAPHEADER" | wc -c` ]
		fi
		if [ $[ $LINELENGTH_INT ] -lt 20 ]; then
			LINELENGTH_INT=20
		fi
		if [ $# -eq 0 ]; then
			#Double sed is required as the first sed only thinks there's one ^, even after we've stuck in newlines.
			sed -e "s/\(.\{1,$LINELENGTH_INT\}\)[[:space:]]\+/\1!!LINEFEED!!/g" -e 's/!!LINEFEED!!/\
/g' | sed -e "s/^/$WRAPHEADER/"
		else
			echo $ENH -n "$* " | sed -e "s/\(.\{1,$LINELENGTH_INT\}\)[[:space:]]\+/\1!!LINEFEED!!/g" -e 's/!!LINEFEED!!/\
/g' | sed -e "s/^/$WRAPHEADER/"
		fi
	} #End of wrap
else	#Fall back on alternate form of the function that doesnt need sed or wc.
	#Checks done on the following function: 1
	wrap () {
		if [ $# -eq 0 ]; then
			while read LINE ; do echo $LINE ; done
		else
			echo $ENH $*
		fi
	} #End of wrap
fi
if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo -n wrap...
#FIXME - this whacks LINELENGTH in the current shell.  LINELENGTH=20 wrap..., perhaps?
	export LINELENGTH=20
	if [ ! "`wrap Hello there, world.`" = \
"Hello there, world." \
	]; then											error wrap-1 ; fi

	if [ ! "`wrap The licenses for most software are designed to take away your freedom to share and change it.`" = \
"The licenses for
most software are
designed to take
away your freedom to
share and change it." \
	]; then											error wrap-2 ; fi

	export LINELENGTH=40
	if [ ! "`wrap The licenses for most software are designed to take away your freedom to share and change it.`" = \
"The licenses for most software are
designed to take away your freedom to
share and change it." \
	]; then											error wrap-3 ; fi

	if [ ! "`echo 'The licenses for most software are designed to take away your freedom to share and change it. ' | wrap`" = \
"The licenses for most software are
designed to take away your freedom to
share and change it." \
	]; then											error wrap-4 ; fi

	unset LINELENGTH
fi



if [ "$DOREGRESSIONTEST" = "YES" ]; then
	echo done.

	echo ---------- Exit with a fanfare ----------
	echo `cat $0 | sed -e 's/#.*//' | grep 'error .* fi' | grep -v regression | wc -l` regression tests successful on $SAMVER

	if [ -d /usr/src/sam-work ]; then
		date >>/usr/src/sam-work/regression-log
		echo `cat $0 | sed -e 's/#.*//' | grep 'error .* fi' | grep -v regression | wc -l` regression tests successful on $SAMVER >>/usr/src/sam-work/regression-log
	fi
	exit 0
fi


