#!/bin/sh
# Regenerates the AmigaOS Hunk reference corpus (workstream W55).
#
# For every case directory here it assembles the `.s` sources with vasm
# (`vasmm68k_mot -Felf`, ELF m68k objects), builds the archives `link.txt`
# asks for, links the result with vlink (`-b amigahunk`) and writes the
# load file as `expected.hunk`. `MANIFEST.txt` records the tool versions
# and every command that ran, so the corpus says what produced it.
#
# The objects and the load files are committed, so `tests/hunk.rs` runs
# without either tool. CI regenerates them and fails if anything changed.
#
#   ./generate.sh              # use $VASM/$VLINK, or vasmm68k_mot/vlink in PATH
#   ./generate.sh --build      # fetch and build both into $CACHE first
#
# Environment:
#   VASM, VLINK   paths to the two binaries
#   AR            archiver (default `ar`)
#   CACHE         where --build unpacks and builds (default
#                 ${TMPDIR:-/tmp}/qld-hunk-tools)
#   JOBS          make parallelism (default 2)
#
# Pinned versions: vasm 2.0f, vlink 0.18a. Upstream ships only a "latest"
# tarball, so --build takes what is there and MANIFEST.txt records what it
# got; a different version that changes the output fails the comparison,
# which is the point.

set -eu

here=$(cd "$(dirname "$0")" && pwd)
cache=${CACHE:-${TMPDIR:-/tmp}/qld-hunk-tools}
jobs=${JOBS:-2}
ar=${AR:-ar}

VASM_URL=http://sun.hasenbraten.de/vasm/release/vasm.tar.gz
VLINK_URL=http://sun.hasenbraten.de/vlink/release/vlink.tar.gz

build_tools() {
	mkdir -p "$cache"
	cd "$cache"
	if [ ! -x "$cache/vasm/vasmm68k_mot" ]; then
		[ -f vasm.tar.gz ] || curl -fsSLO "$VASM_URL"
		rm -rf vasm
		tar xzf vasm.tar.gz
		( cd vasm && make -j"$jobs" CPU=m68k SYNTAX=mot )
	fi
	if [ ! -x "$cache/vlink/vlink" ]; then
		[ -f vlink.tar.gz ] || curl -fsSLO "$VLINK_URL"
		rm -rf vlink
		tar xzf vlink.tar.gz
		( cd vlink && make -j"$jobs" )
	fi
	VASM=$cache/vasm/vasmm68k_mot
	VLINK=$cache/vlink/vlink
	export VASM VLINK
}

if [ "${1-}" = "--build" ]; then
	build_tools
fi

vasm=${VASM:-$(command -v vasmm68k_mot || true)}
vlink=${VLINK:-$(command -v vlink || true)}
if [ -z "$vasm" ] || [ -z "$vlink" ]; then
	echo "generate.sh: vasm and vlink are needed; run with --build" >&2
	exit 1
fi

manifest=$here/MANIFEST.txt
# Run with no input, both tools print their banner and then write their
# default output file, so the version probes run in a scratch directory.
probe=$(mktemp -d)
{
	echo "# AmigaOS Hunk reference corpus, generated by generate.sh."
	echo "# Do not edit by hand; re-run the script instead."
	echo
	echo "vasm: $(cd "$probe" && "$vasm" 2>&1 </dev/null | sed -n '1s/ (c).*//p')"
	echo "vlink: $(cd "$probe" && "$vlink" 2>&1 </dev/null | sed -n '1s/ (c).*//p')"
	echo
} > "$manifest"
rm -rf "$probe"

for case_dir in "$here"/*/; do
	[ -f "$case_dir/link.txt" ] || continue
	name=$(basename "$case_dir")
	cd "$case_dir"
	rm -f ./*.o ./*.a expected.hunk
	echo "## $name" >> "$manifest"
	for src in *.s; do
		obj=${src%.s}.o
		echo "$vasm -Felf -quiet -o $obj $src"
		"$vasm" -Felf -quiet -o "$obj" "$src"
		echo "  vasmm68k_mot -Felf -quiet -o $obj $src" >> "$manifest"
	done
	flags=$(sed -n 's/^flags //p' link.txt)
	while read -r kind rest; do
		[ "$kind" = archive ] || continue
		lib=$(echo "$rest" | cut -d' ' -f1)
		members=$(echo "$rest" | cut -s -d' ' -f2-)
		# `D` (deterministic: zeroed timestamps, uid, gid and mode)
		# keeps the committed archive reproducible.
		# shellcheck disable=SC2086
		"$ar" rcsD "$lib" $members
		echo "  ar rcsD $lib $members" >> "$manifest"
	done < link.txt
	objects=$(sed -n 's/^objects //p' link.txt)
	if grep -q '^error ' link.txt; then
		# A case both linkers must reject: only the objects are kept.
		echo "  (no vlink run: $(sed -n 's/^error //p' link.txt))" >> "$manifest"
		echo >> "$manifest"
		continue
	fi
	# shellcheck disable=SC2086
	"$vlink" -b amigahunk $flags -o expected.hunk $objects
	echo "  vlink -b amigahunk $flags -o expected.hunk $objects" >> "$manifest"
	echo >> "$manifest"
done

echo "wrote $manifest"
