#!/bin/bash
nl='
'
safeIFS='	'
safeIFS=" $safeIFS$nl"
IFS=$safeIFS
allu=QWERTYUIOPASDFGHJKLZXCVBNM
alll=qwertyuiopasdfghjklzxcvbnm
alln=0123456789

test_n() {
	test x"$1" = x"" || return 0
	return 1
}

test_z() {
	test x"$1" = x""
}

genopt_die() {
	if test_z "$1"; then
		echo >&2 "E: invalid input in '$srcfile': '$line'"
	else
		echo >&2 "E: $*"
		echo >&2 "N: in '$srcfile': '$line'"
	fi
	rm -f "$bn.gen"
	exit 1
}

genopt_soptc() {
	optc=`echo "$line" | sed 's/^[<>]\(.\).*$/\1/'`
	test x"$optc" = x'|' && return
	optclo=`echo "$optc" | tr $allu $alll`
	if test x"$optc" = x"$optclo"; then
		islo=1
	else
		islo=0
	fi
	sym=`echo "$line" | sed 's/^[<>]/|/'`
	o_str=$o_str$nl"<$optclo$islo$sym"
}

genopt_scond() {
	case x$cond in
	x)
		cond=
		;;
	x*' '*)
		cond=`echo "$cond" | sed 's/^ //'`
		cond="#if $cond"
		;;
	x'!'*)
		cond=`echo "$cond" | sed 's/^!//'`
		cond="#ifndef $cond"
		;;
	x*)
		cond="#ifdef $cond"
		;;
	esac
}

do_genopt() {
	srcfile=$1
	test -f "$srcfile" || genopt_die Source file \$srcfile not set.
	bn=`basename "$srcfile" | sed 's/.opt$//'`
	o_hdr='/* +++ GENERATED FILE +++ DO NOT EDIT +++ */'
	o_gen=
	o_str=
	o_sym=
	ddefs=
	state=0
	exec <"$srcfile"
	IFS=
	while IFS= read line; do
		IFS=$safeIFS
		case $state:$line in
		2:'|'*)
			# end of input
			o_sym=`echo "$line" | sed 's/^.//'`
			o_gen=$o_gen$nl"#undef F0"
			o_gen=$o_gen$nl"#undef FN"
			o_gen=$o_gen$ddefs
			state=3
			;;
		1:@@)
			# start of data block
			o_gen=$o_gen$nl"#endif"
			o_gen=$o_gen$nl"#ifndef F0"
			o_gen=$o_gen$nl"#define F0 FN"
			o_gen=$o_gen$nl"#endif"
			state=2
			;;
		*:@@*)
			genopt_die ;;
		0:/\*-|0:\ \**|0:)
			o_hdr=$o_hdr$nl$line
			;;
		0:@*|1:@*)
			# start of a definition block
			sym=`echo "$line" | sed 's/^@//'`
			if test $state = 0; then
				o_gen=$o_gen$nl"#if defined($sym)"
			else
				o_gen=$o_gen$nl"#elif defined($sym)"
			fi
			ddefs="$ddefs$nl#undef $sym"
			state=1
			;;
		0:*|3:*)
			genopt_die ;;
		1:*)
			# definition line
			o_gen=$o_gen$nl$line
			;;
		2:'<'*'|'*)
			genopt_soptc
			;;
		2:'>'*'|'*)
			genopt_soptc
			cond=`echo "$line" | sed 's/^[^|]*|//'`
			genopt_scond
			case $optc in
			'|') optc=0 ;;
			*) optc=\'$optc\' ;;
			esac
			IFS= read line || genopt_die Unexpected EOF
			IFS=$safeIFS
			test_z "$cond" || o_gen=$o_gen$nl"$cond"
			o_gen=$o_gen$nl"$line, $optc)"
			test_z "$cond" || o_gen=$o_gen$nl"#endif"
			;;
		esac
	done
	case $state:$o_sym in
	3:) genopt_die Expected optc sym at EOF ;;
	3:*) ;;
	*) genopt_die Missing EOF marker ;;
	esac
	echo "$o_str" | sort | while IFS='|' read x opts cond; do
		IFS=$safeIFS
		test_n "$x" || continue
		genopt_scond
		test_z "$cond" || echo "$cond"
		echo "\"$opts\""
		test_z "$cond" || echo "#endif"
	done | {
		echo "$o_hdr"
		echo "#ifndef $o_sym$o_gen"
		echo "#else"
		cat
		echo "#undef $o_sym"
		echo "#endif"
	} >"$bn.gen"
	IFS=$safeIFS
	return 0
}

do_genopt "$1"
