#!/bin/awk -f
BEGIN {
	fname="\"$fname\""  # constants so I don't have to write it out
	# dirname="\"$dirname\""
	or_die="|| exit $?"

	if ("RSFILTER" in ENVIRON) {
		# clean the filter file
		printf "" >ENVIRON["RSFILTER"]
	}

	func_num=0
	has_cond=""
}

function escaped(str) {
	gsub(/\\/, "\\\\", str)
	# gsub(/\n/, "\\n", str)
	gsub(/([\\\t"`${}\[\]])/, "\\\\&", str)
	return str
}

function quoted(str) {
	if(str ~ "^[a-zA-Z0-9_./]+$")
		return str
	gsub(/'/, "'\\''", str)
	return "'" str "'"
	# return "\"" escaped(str) "\""
}

function print_i(str) {  # print with indent
	print indent str
}

function print_d(str) {  # print or die
	print indent str " " or_die
}

function print_b(str) {  # print begin block
	print indent str
	indent = indent "\t"
}

function print_m(str) {  # print mid-block deindented
	print substr(indent, 2) str
}

function print_e(str) {  # print end block
	indent = substr(indent, 2)
	print indent str
}

function print_cond(statement, suffix) {  # TODO
	if(has_cond == "") {
		print_b("if ! $check_only; then")
		print_d("{ "statement"\n}"suffix)
		print_e("fi")
	} else {
		if(suffix) {
			funcs["do_" has_cond] = "{ "statement"\n}"suffix
		} else {
			funcs["do_" has_cond] = statement
		}
		print_d("req " has_cond)
		has_cond = ""
	}
}

function print_rsfilter(str) {
	if ("RSFILTER" in ENVIRON) {
		print str >>ENVIRON["RSFILTER"]
	# } else {
	# 	print str >>"/dev/stderr"
	}
}

# take tab-delimited token from statement variable and return it
function get_till_tab(    result) {
	if(match(statement, /\t/)) {
		result = substr(statement, 1, RSTART-1)
		statement = substr(statement, RSTART+1)
	} else {
		result = statement
		statement = ""
	}
	return result
}

function get_argument(whole_statement,    result) {
	if(whole_statement) {
		result = statement
		statement = ""
	} else {
		result = get_till_tab()
	}
	return result
}

function shellfunc(fun, flags) {
	print_d("flags "quoted(flags)"; "fun)
}

function process_statement() {
	while(statement) {
		command = get_till_tab()
		if(!command) continue
		cchar = substr(command, 1, 1)
		crest = substr(command, 2)

		# check before the command is processed if we have dangling "?"
		if(cchar != "!" && has_cond != "") {
			printf "%s:%s: ? is not followed by ! (superfluous condition): %s\n", FILENAME, FNR, \
				   cchar crest " '" statement "'" >"/dev/stderr"
			if(!WARN_ONLY) {
				exit 1
			}
		}

		# set current fname all subsequent operations will be performed on
		if(cchar == "/") {
			curpath = crest
			# fix up the path
			if(match(crest, "/+$")) {
				crest = substr(crest, 1, length(crest) - RLENGTH)
			}
			crest = "./" crest

			print ""
			print_i("fname=" quoted(crest))
			match(crest, /.*\//)
			# print_i("dirname=" quoted(substr(crest, 1, RLENGTH-1)))
			continue
		}

		if(cchar == "+") {
			print_rsfilter("+ /" curpath crest)
			continue
		}

		if(cchar == "-") {
			print_rsfilter("- /" curpath crest)
			continue
		}

		if(cchar == "o") {
			print_i("o "crest)
			continue
		}

		if(cchar == "m") {
			print_i("m "crest)
			continue
		}

		if(cchar == "u") {
			print_i("umask "crest)
			continue
		}

		# remove
		if(cchar == "r") {
			shellfunc("r", crest)
			continue
		}

		# create file
		if(cchar == "f") {
			shellfunc("f", crest)
			continue
		}

		# symbolic link
		if(cchar ~ /[lL]/) {
			shellfunc("l "quoted(get_argument(cchar == "L")), crest)
			continue
		}

		# directory
		if(cchar == "d") {
			shellfunc("d", crest)
			continue
		}

		# Cat, Copy, Content; eats rest of statement and puts it into the file
		# Binary, Base64; decodes the arguments and changes file content
		# heXdump; decodes the arguments and replaces file content
		if(cchar ~ /[bBcCX]/) {
			shellfunc("f 1", crest)
			content = get_argument(cchar ~ /[BCX]/)

			func_name = "fn" func_num++

			if(cchar ~ /[bB]/) {
				funcs[func_name] = "\tbase64 <<<"quoted(content)
			} else if(cchar ~ /[X]/) {
				funcs[func_name] = "\txxd -r <<<"quoted(content)
			} else {
				# unless disabled with the N flag, append newline at the end of
				# last line, if not already present
				printf_fmt = ( \
					crest ~ /n/ || (crest !~ /N/ && content !~ /\n$/) \
					) ? "%s\\n" : "%s"
				if(printf_fmt == "%s" || length(content) < 1800) {
					# TODO: split into several when needed
					funcs[func_name] = "\tprintf '"printf_fmt"' "quoted(content)
				} else {
					funcs[func_name] = "\tcat <<<"quoted(content)
				}
			}

			if(crest ~ /a/) {
				print_cond(func_name, ">>"fname)
			} else if(has_cond == "") {
				print_i("c " func_name)
			} else {
				print_cond("c "func_name)
			}
			continue
		}

		# run shell command
		if(cchar == "!") {
			# use as Filter
			if(crest ~ /f/) {
				if(crest ~ /c/) {
					shellfunc("f", crest)
				} else {
					shellfunc("req type_or_missing f", crest)
				}
				print_cond("\n" \
					"\t{ "statement"\n} <"fname" >"fname".tmp.$$ " or_die "\n" \
					"\tc cat "fname".tmp.$$\n" \
					"\trm "fname".tmp.$$ " or_die "\n")
			# use file as Input
			} else if(crest ~ /i/) {
				print_cond(statement, "<"fname)
			# use file as Output
			} else if(crest ~ /o/) {
				shellfunc("req type_or_missing f", crest)
				print_cond(statement, ">"fname)
			# Append to file
			} else if(crest ~ /a/) {
				shellfunc("req type_or_missing f", crest)
				print_cond(statement, ">>"fname)
			# do nothing special with file
			} else {
				print_cond(statement)
			}
			statement = ""
			continue
		}

		# shell condition
		if(cchar == "?") {
			has_cond = func_num++
			if(crest ~ /i/) {
				funcs["check_" has_cond] = ( \
					"{ "statement"\n} <"fname \
				)
			} else {
				funcs["check_" has_cond] = statement
			}
			statement = ""
			continue
		}

		# if none above matched
		printf "%s:%s: unrecognised statement: %s\n", FILENAME, FNR, \
			cchar crest " '" statement "'" >"/dev/stderr"
		if(!WARN_ONLY) {
			exit 1
		}
		statement = ""
	}
}

function parse_line(line) {
	if(!line) {  # empty line, ignore
		return
	}
	if(line ~ /^#/) {  # comment, ignore
		return
	}
	if(line ~ /^\t/) {  # continuation, append to statement
		statement = statement "\n" substr(line, 2)
	} else {  # new statement
		process_statement()
		statement = line
	}
}

function print_functions() {
	for( func_name in funcs ) {
		print func_name "(){\n" funcs[func_name] "\n}\n"
	}
}

BEGIN {
	print_b("check_main() {")
}

{ parse_line($0) }

END {
	process_statement()
	print_e("}")
	print_b("do_main() {")
	print_i("true")
	print_e("}")
	print ""
	print_functions()
	print_i("req main")
}