#!/bin/sh

die() {
	echo "$*" >&2
	exit 1
}

test "$1" || die "usage: gen_syscalls [input] [output]"

find_label() {
	line=$(printf '%s\n' "$labels" | grep -e "$1 " | head -n 1)
	if test "$line"; then printf '%d\n' "${line#* }"; fi
}

line_cut_next() {
	next=${line%% *}
	oline=$line
	line=${line#* }
	if test "$line" = "$oline"; then line= ; fi
}

put_cmp() {
	line_cut_next
	val=${next#cha_}
	line_cut_next
	label=$(find_label "$next")
	test "$label" || die "missing label $next"
	label=$(($label - 1 - $ip))
	printf '\t%s(%s, %d),\n' "$1" "$val" "$label"
}

put_load() {
	line_cut_next
	printf '\tCHA_BPF_LOAD(%s),\n' "$next"
}

put_ret() {
	line_cut_next
	case $next in
	allow)	val=SECCOMP_RET_ALLOW ;;
	trap)	val=SECCOMP_RET_TRAP ;;
	kill)	val=SECCOMP_RET_KILL_PROCESS ;;
	errno)	val="SECCOMP_RET_ERRNO | ($line & SECCOMP_RET_DATA)" ;;
	*)	die "wrong retval $line" ;;
	esac
	printf '\tCHA_BPF_RET(%s),\n' "$val"
}

sed -ne '/^: start$/,$p' "$1" >"$2~"

ip=0
while IFS= read -r line
do	line=${line%%#*}
	case $line in
	': '*)	line_cut_next
		if test -n "$labels"
		then	labels="$labels
$line $ip"
		else	labels="$line $ip"
		fi
		;;
	'')	;;
	*)	ip=$((ip + 1));;
	esac
done < "$2~"

ip=0
while IFS= read -r line
do	line_cut_next
	case $next in
	:)	continue ;;
	ret)	put_ret ;;
	ifeq)	put_cmp CHA_BPF_JE;;
	ifne)	put_cmp CHA_BPF_JNE;;
	ifle)	put_cmp CHA_BPF_JLE;;
	load)	put_load;;
	'')	continue;;
	*)	die "unexpected instruction $next" ;;
	esac
	ip=$(($ip + 1))
done < "$2~" >"$2~~"

mv "$2~~" "$2~"

printf '#define EXPECTED_COUNT %d\n' "$ip" >>"$2~"

mv "$2~" "$2"
