#!/bin/sh

echo
echo ".a to .ixlibrary converter, version 2.0"
echo

prefix="/gg/share/a2ixlibrary"

eval `/gg/bin/date "+day=%d;month=%m;year=%y"`
day=`expr $day + 0`
month=`expr $month + 0`
year=`expr $year + 0`
debug=0
resident=-resident
modifier=W

while true
do
	if [ "$1" = "-debug" ]
	then
		debug=1
		shift
		echo "Entered debug mode"
	elif [ "$1" = "-32" ]
	then
		resident="-resident32 -m68020"
		modifier=L
		shift
	else
		break
	fi
done

if [ X"$1" = X ]
then
	data=a2ixlibrary.data
else
	data=$1
fi

if [ ! -f $data ]
then
	echo could not find $data!
	exit 2
fi

echo scan $data
name=`egrep "^#define NAME " $data | sed -e "s/#define NAME *//" -e "s/ *$//"`
filename=`egrep "^#define FILENAME " $data | sed -e "s/#define FILENAME *//" -e "s/ *$//"`
safename=`$prefix/a2ixsafename $name`
libs=`egrep "^#define LIBS_LIST " $data | sed -e "s/#define LIBS_LIST *//" -e "s/ *$//"`
dirs=`egrep "^#define LINK_DIRS " $data | sed -e "s/#define LINK_DIRS *//" -e "s/ *$//"`
internals=`egrep "^#define INTERNALS " $data`

if [ X"$filename" = X ]
then
	filename=$name
fi

if [ ! -f lib$filename.a ]
then
	echo could not find lib$filename.a!
	exit 2
fi

if [ X"$libs" != X ]
then
	for i in $libs
	do
		if [ -f $prefix/ldscripts/${i}.x ]
		then
			shared_libs="$shared_libs $i"
		else
			static_libs="$static_libs -l$i"
		fi
	done
fi

if [ X"$dirs" != X ]
then
	for i in $dirs
	do
		link_dirs="$link_dirs -L$i"
	done
fi

rm -rf amigaobj
mkdir amigaobj

if [ ! X"$internals" = X ]
then
	cp $data amigaobj/x.c
	echo "
	INTERNALS" >>amigaobj/x.c
	internals=`gcc -E -P amigaobj/x.c`
	rm -f amigaobj/x.c
fi

echo collect init routines
call_inits="#define CALL_INITS "`egrep -s amiga_init_ *.c | sed -e 's/^.*amiga/amiga/' -e 's/(void)/();\\\\/' | sort`

cd amigaobj

echo find public functions in lib$filename.a
nm --extern-only ../lib$filename.a | egrep " T " | egrep -v "_amiga_init_" | sort +2 >f2.lst
cut -c 13- <f2.lst >f.lst

echo create lib_funcs.s
echo '.text
.global ___link_text_hashes
___link_text_hashes:' >lib_funcs.s
$prefix/string_hash <f.lst >>lib_funcs.s
echo '.global ___link_text_offsets
___link_text_offsets:' >>lib_funcs.s
sed -e 's/^/.long _/' <f.lst >>lib_funcs.s
echo ".long -1" >>lib_funcs.s
rm -f f.lst

echo >shared_ptr.s
if [ X"$shared_libs" != X ]
then
	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		echo find "*_${safei}_shared_ptr" externals in lib$filename.a
		nm --extern-only ../lib$filename.a | egrep _${safei}_shared_ptr | \
		  sed -e "s/_${safei}_shared_ptr$//" | cut -c 13- | sort | uniq >sp.lst
		echo ".data
		.global __${safei}_shared_ptr_table
		__${safei}_shared_ptr_table:
		.long " `wc sp.lst | cut -c -7` >>shared_ptr.s
		$prefix/string_hash ${safei} <sp.lst >>shared_ptr.s
	done
fi

echo find globals in lib$filename.a
nm --extern-only ../lib$filename.a | egrep " D | C " | sort +2 >g2.lst
if [ X"$internals" != X ]
then
	echo remove internals
	for i in $internals
	do
		egrep -v " ${i}$" <g2.lst >gg.lst
		cp gg.lst g2.lst
	done
	rm -f gg.lst
fi 
cut -c 13- <g2.lst >g.lst

echo create lib_data.s
echo '.text
.global ___link_data_hashes
___link_data_hashes:' >lib_data.s
$prefix/string_hash <g.lst >>lib_data.s
echo '.data
.global ___link_data_offsets
___link_data_offsets:' >>lib_data.s
sed -e 's/^/.long _/' <g.lst >>lib_data.s
echo ".long -1" >>lib_data.s

echo create $filename.h
mkdir -p /gg/include/a2ixlibrary
hdr=/gg/include/a2ixlibrary/$filename.h
echo "/* This file is automatically generated by a2ixlibrary. Do not change.
   Only shared library sources can include this header, do not use this header
   in your own programs! */
#ifndef UNDEF_amiga_$safename
" >$hdr
sed -e 's/^/extern void *__/' -e 's/$/_'$safename'_shared_ptr;/' <g.lst >>$hdr
sed -e 's/^\(.*\)/#define \1 (*((__typeof__(\1) *)__\1_'$safename'_shared_ptr))/' <g.lst >>$hdr
echo "#define UNDEF_amiga_$safename
#else" >>$hdr
sed -e 's/^/#undef /' <g.lst >>$hdr
echo "#undef UNDEF_amiga_$safename
#endif" >>$hdr
rm -f g.lst

echo create a2ixlibrary.h
cd ..
cp $data amigaobj/a2ixlibrary.h
cd amigaobj
cat <<EOF >>a2ixlibrary.h
#define xstr(s) str(s)
#define str(s) #s
#define SNAME xstr(NAME)
#define SVERSION xstr(VERSION)
#define SREVISION xstr(REVISION)
#define FULLNAME \"lib$name.ixlibrary\"
#define IDSTRING \"lib$name \" SVERSION \".\" SREVISION \" ($day.$month.$year)\"
#define BASE ${safename}Base
#define CLOSEINST __${safename}CloseInstance
#define RELOCINST __${safename}RelocateInstance
#define SETVARSINST __${safename}SetVarsInstance
#define TFSTART _shared_textfunctions_start_lib${safename}
#define TDSTART _shared_textdata_start_lib${safename}
#define DFSTART _shared_datafunctions_start_lib${safename}
#define DDSTART _shared_datadata_start_lib${safename}
$call_inits

EOF

if [ X"$shared_libs" != X ]
then
	echo "	#define INSTANCE_LIBS void _stext(); void _etext(); \\
		void _sdata(); void __text_size(); \\" >>a2ixlibrary.h
	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		linklibs="$linklibs -l$i" 
		echo "struct Library *${safei}Base = NULL; \\" >>a2ixlibrary.h
		echo "extern unsigned long _${safei}_shared_ptr_table[]; \\" >>a2ixlibrary.h
		echo "void _shared_textfunctions_start_lib${safei}(); \\" >>a2ixlibrary.h
		echo "void _shared_datafunctions_start_lib${safei}(); \\" >>a2ixlibrary.h
		echo "void _shared_datadata_start_lib${safei}(); \\" >>a2ixlibrary.h
		echo "asm(\".text\"); \\
asm(\"___${safei}RelocateInstance: 	movel	a4@(_${safei}Base:$modifier),a0\"); \\
asm(\"jmp	a0@(-36:w)\"); asm(\".data\"); \\" >>a2ixlibrary.h
	done
	echo "asm(\".text\"); static int open_libs(void) { \\
long offset = _etext -_sdata + 4 + 4 * *((long *)__datadata_relocs); \\
long A4; asm volatile (\"movel a4,%0\" : \"=g\" (A4)); A4 -= 0x7ffe; \\" >>a2ixlibrary.h

	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		echo "if (!(${safei}Base = OpenLibrary(\"lib$i.ixlibrary\", 0))) return 0; \\" >>a2ixlibrary.h
		echo "if (!__${safei}RelocateInstance( \\
                      _stext, _shared_textfunctions_start_lib${safei} + offset, NULL, \\
                      (void *)A4, _shared_datafunctions_start_lib${safei} + offset, \\
			          _shared_datadata_start_lib${safei} + offset, \\
		      _${safei}_shared_ptr_table)) \\" >>a2ixlibrary.h
                echo "{ CloseLibrary(${safei}Base); return 0; } \\" >>a2ixlibrary.h
	done
	echo "CacheClearE(_stext, (long)__text_size, CACRF_ClearI|CACRF_ClearD); \\" >>a2ixlibrary.h
	echo "return 1; } \\" >>a2ixlibrary.h
	echo "static void close_libs(void) { \\" >>a2ixlibrary.h
	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		echo "if (${safei}Base) CloseLibrary(${safei}Base); \\" >>a2ixlibrary.h
	done
	echo "}" >>a2ixlibrary.h

	echo "	#define MISC_SETVARS asm(\".text\");\\" >>a2ixlibrary.h
	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		echo "asm(\"___${safei}SetVarsInstance: movel a4@(_${safei}Base:$modifier),a0\"); \\
asm(\"jmp	a0@(-42:w)\"); \\" >>a2ixlibrary.h
	done
	echo "
#define CALL_SETVARS \\" >>a2ixlibrary.h
	for i in $shared_libs
	do
		safei=`$prefix/a2ixsafename $i`
		echo "__${safei}SetVarsInstance(argc, ixbase, errnoptr, ctype, sf);\\" >>a2ixlibrary.h
	done
	echo >>a2ixlibrary.h
fi

echo assemble start.S
gcc -I. -c $prefix/start.S -o start.o
echo compile instance.c

# This source *must* be compiled with -malways-restore-a4!
gcc $resident -malways-restore-a4 -I. -c -O $prefix/instance.c -o instance.o
echo compile relocate.c
gcc -I. $resident -mrestore-a4 -c -O $prefix/relocate.c -o relocate.o
echo compile setvars.c
gcc -I. $resident -mrestore-a4 -c -O $prefix/setvars.c -o setvars.o
echo assemble lib_data.s, lib_funcs.s and shared_ptr.s
gcc -c -O lib_data.s
gcc -c -O lib_funcs.s
gcc -c -O shared_ptr.s

echo create link script
cp $prefix/amiga_lib_script.x .

if [ X"$shared_libs" != X ]
then
	for i in $shared_libs
	do
		cat $prefix/ldscripts/${i}.x >>amiga_lib_script.x
	done
fi
echo "}}" >>amiga_lib_script.x

if [ X"$internals" != X ]
then
	echo rename internals
	for i in $internals
	do
		sed -e "s/${i}/XX${i}/g" <amiga_lib_script.x >a
		cp a amiga_lib_script.x
	done
	rm -f a
fi 

echo link lib$filename.ixlibrary
gcc -static $resident -o ../lib$filename.ixlibrary -nostdlib -nostartfiles -L.. start.o \
                instance.o relocate.o setvars.o lib_data.o lib_funcs.o shared_ptr.o \
		-l$filename $static_libs -lc -lgcc -lc -Xlinker -Tamiga_lib_script.x $link_dirs

if [ ! -f ../lib$filename.ixlibrary ]
then
	echo failed to link lib$filename.ixlibrary
	rm -f ../lib$filename.a
	exit 2
fi

echo create $filename.x
mkdir -p $prefix/ldscripts
echo "/* $shared_libs */" >$prefix/ldscripts/$filename.x
nm --extern-only ../lib$filename.ixlibrary | sort +2 | egrep " T " >f1.lst
join -j 3 f1.lst f2.lst -o "1.1 1.2 1.3" | sort >f.lst
perl $prefix/deltafunctions.pl `$prefix/a2ixgetsize ../lib$filename.ixlibrary` \
	$safename <f.lst >>$prefix/ldscripts/$filename.x
rm -f f1.lst f2.lst f.lst

nm --extern-only ../lib$filename.ixlibrary | sort +2 | egrep " D " >g1.lst
join -j 3 g1.lst g2.lst -o "1.1 1.2 1.3" | sort >g.lst
perl $prefix/deltadata.pl `$prefix/a2ixgetsize ../lib$filename.ixlibrary` \
	$safename <g.lst >>$prefix/ldscripts/$filename.x
rm -f g1.lst g2.lst g.lst

echo compile auto_init.c
gcc -g -I. -c -O $prefix/auto_init.c -o auto_init.o

cd ..

echo create new lib${filename}_ixlibrary.a
rm -f lib${filename}_ixlibrary.a
ar q lib${filename}_ixlibrary.a amigaobj/auto_init.o
ranlib lib${filename}_ixlibrary.a

echo postprocess lib$filename.ixlibrary
postlink -library lib$filename.ixlibrary

if [ "$debug" -ne 0 ]
then
	cp lib$filename.ixlibrary amigaobj/lib$filename.debug
fi

strip lib$filename.ixlibrary

if [ "$debug" -eq 0 ]
then
	rm -rf amigaobj
fi

exit 0
