#!/bin/sh
#
# Usage: gen.sh <newkern> <oldkern>

# Label size
ls=10
# column size
cs=20
# diff column siz
ds=10
printrow()
{
	printf "%${ls}.${ls}s  %-${cs}.${cs}s %-${cs}.${cs}s | %s%${ds}s\n" "$1" "$2" "$3" "$5" "$4"
}
header()
{
	printrow "" "Old" "New" "diff"
}
printnums()
{
	local vname nval oval mark
	# diff and xdiff are not local

	vname="$1"
	oval="$2"
	nval="$3"
	extra="$4"
	xdiff=$(($nval - $oval))
	if [ "$nval" -gt "$oval" ] ; then
		diff=$(($nval - $oval))
		mark="+"
	else
		diff=$(($oval - $nval))
		mark="-"
	fi
	printrow "$vname:" "$oval" "$nval" "${diff}$4" $mark
}

if [ "$1" != "-dir" ] ; then
	DIR=run.`date +%Y-%m-%d:%H%M`
	mkdir -p "$DIR"
	edir=`dirname "$0"`
	eprog=`basename "$0"`
	# Since each portion of a pipeline is a subshell, a plain
	# "exec ... | tee ... " doesn't do what you'd expect.
	sh "$edir/$eprog" -dir "$DIR" "$@" | tee "$DIR/out"
	if [ $? -ne 0 ] ; then
		echo "ERROR: Failed to exec with -dir '$DIR'"
		exit 1
	fi
	exit 0
fi

DIR=$2
shift 2
if [ ! -d "$DIR" ] ; then
	echo "ERROR: '$DIR' doesn't exist!"
	exit 1
fi

NKERN=${1:-/netbsd}
OKERN=${2:-/onetbsd}

nm -B --size-sort -t d -r "$NKERN" > "${DIR}/${NKERN}.size"
nm -B --size-sort -t d -r "$OKERN" > "${DIR}/${OKERN}.size"

nkern_size=`size -A "$NKERN" | grep '^\Total' | awk ' { print $2 } '`
nkern_text=`size -A "$NKERN" | grep '^\.text' | awk ' { print $2 } '`
nkern_data=`size -A "$NKERN" | grep '^\.data' | awk ' { print $2 } '`
nkern_bss=`size -A "$NKERN" | grep '^\.bss' | awk ' { print $2 } '`
okern_size=`size -A "$OKERN" | grep '^\Total' | awk ' { print $2 } '`
okern_text=`size -A "$OKERN" | grep '^\.text' | awk ' { print $2 } '`
okern_data=`size -A "$OKERN" | grep '^\.data' | awk ' { print $2 } '`
okern_bss=`size -A "$OKERN" | grep '^\.bss' | awk ' { print $2 } '`

what $NKERN
what $OKERN
echo 
cs=10
ds=6
header
printrow Name: "$NKERN" "$OKERN" ""
printnums "size" $okern_size $nkern_size
printnums "text" $okern_text $nkern_text
printnums "data" $okern_data $nkern_data
printnums "bss" $okern_bss $nkern_bss

nkern_nsyms=`cat "${DIR}/${NKERN}.size" | wc -l`
okern_nsyms=`cat "${DIR}/${OKERN}.size" | wc -l`
printnums "Nsyms" $okern_nsyms $nkern_nsyms

awk ' { print $3 } ' ${DIR}/${NKERN}.size | sort > ${DIR}/${NKERN}.syms
awk ' { print $3 } ' ${DIR}/${OKERN}.size | sort > ${DIR}/${OKERN}.syms

cs=20
ds=-15
echo
header
oIFS="$IFS"
IFS="
"
totalsize=0
for sym in `comm -3 "${DIR}/${NKERN}.syms" "${DIR}/${OKERN}.syms"` ; do
	case "$sym" in
	"	"*)
		sym=${sym##	}
		size=`grep " ${sym}\$" "${DIR}/${OKERN}.size" | awk ' { print $1 + 0; exit; } '`
		totalsize=$(($totalsize - $size))
		printrow "" "" "${sym}" "removed (-$size)"
		;;
	*)
		size=`grep " $sym\$" "${DIR}/${NKERN}.size" | awk ' { print $1 + 0; exit; } '`
		totalsize=$(($totalsize + $size))
		printrow "" "${sym}" "" "added   (+$size)"
		;;
	esac
done
IFS="$oIFS"
syms_added=`comm -13 "${DIR}/${NKERN}.syms" "${DIR}/${OKERN}.syms" | wc -l`
syms_removed=`comm -23 "${DIR}/${NKERN}.syms" "${DIR}/${OKERN}.syms" | wc -l`
printrow "-------" "--Add--" "--Del--" "-------"
if [ $totalsize -gt 0 ] ; then
	totalsize=+$totalsize
fi
printnums Total $syms_added $syms_removed "   ($totalsize)"


cs=6
ds=15
ls=20
echo
printrow "" "Old" "New" "symbols size change"
ds=6
# Identify size change in all common symbols.
oIFS="$IFS"
IFS="
"
pstate=.oO
ps1=-
ps2=.
ps3=-
echo -n "$pstate" 1>&2
skipcount=0
totalsize=0
for sym in `comm -12 "${DIR}/${NKERN}.syms" "${DIR}/${OKERN}.syms"` ; do
	# +0 to strip leading zeros
	
	nsize=`grep " $sym\$" "${DIR}/${NKERN}.size" | awk ' { print $1 + 0; exit; } '`
	osize=`grep " $sym\$" "${DIR}/${OKERN}.size" | awk ' { print $1 + 0; exit; } '`
	if [ $nsize != $osize ] ; then
		echo -n "" 1>&2
		skipcount=0
		printnums "$sym" $osize $nsize
		echo "$sym" $osize $nsize $xdiff >> "${DIR}/syms.size"
		
		totalsize=$(($totalsize + $xdiff))
	else
		skipcount=$(($skipcount + 1))
		if [ $(($skipcount % 10)) -eq 0 ] ; then
			echo -n "${ps1}${ps2}${ps3}" 1>&2
			case "$ps1" in
			-)
				ps1=/
				;;
			/)
				ps1=\|
				;;
			\|)
				ps1=\\
				;;
			\\)
				ps1=-
				;;
			esac

			case "$ps2" in
			.)
				ps2=o
				;;
			o)
				ps2=O
				;;
			O)
				ps2=oo
				;;
			oo)
				ps2=.
				;;
			esac

			case "$ps3" in
			-)
				ps3=\\
				;;
			/)
				ps3=-
				;;
			\|)
				ps3=/
				;;
			\\)
				ps3=\|
				;;
			esac

		fi
	fi
done
printf "" 1>&2
IFS="$oIFS"

printrow Total "" "" $totalsize
