#!/usr/bin/env sh

### Script: includefile
##
## ファイルをインクルードする。
##
## Metadata:
##
##   id - 58a1cbfd-8bc9-40d5-8013-cb765d3fd182
##   author - <qq542vev at https://purl.org/meta/me/>
##   version - 0.2.0
##   date - 2022-09-13
##   since - 2022-07-05
##   copyright - Copyright (C) 2022-2022 qq542vev. Some rights reserved.
##   license - <CC-BY at https://creativecommons.org/licenses/by/4.0/>
##   package - w3mplus
##
## See Also:
##
##   * <Project homepage at https://github.com/qq542vev/w3mplus>
##   * <Bug report at https://github.com/qq542vev/w3mplus/issues>
##
## Help Output:
##
## ------ Text ------
## Usage:
##   includefile [OPTION]... OUTPUT_DIR [FILE]...
##
## Options:
##   -V,     --{no-}verbose      冗長な表示を行う
##   -h,     --help              このヘルプを表示して終了する
##   -v,     --version           バージョン情報を表示して終了する
##
## Exit Status:
##     0 - successful termination
##    64 - command line usage error
##    65 - data format error
##    66 - cannot open input
##    67 - addressee unknown
##    68 - host name unknown
##    69 - service unavailable
##    70 - internal software error
##    71 - system error (e.g., can't fork)
##    72 - critical OS file missing
##    73 - can't create (user) output file
##    74 - input/output error
##    75 - temp failure; user is invited to retry
##    76 - remote error in protocol
##    77 - permission denied
##    78 - configuration error
##   129 - received SIGHUP
##   130 - received SIGINT
##   131 - received SIGQUIT
##   143 - received SIGTERM
## ------------------

readonly 'VERSION=includefile 0.2.0'

. 'initialize.sh'
. 'option_error.sh'

# @getoptions
parser_definition() {
	setup REST abbr:true error:optuon_error plus:true no:0 help:usage \
		-- 'Usage:' "  ${2##*/} [OPTION]... OUTPUT_DIR [FILE]..." \
		'' 'Options:'

	flag  verbose -V --{no-}verbose init:@no -- '冗長な表示を行う'
	disp  :usage  -h --help    -- 'このヘルプを表示して終了する'
	disp  VERSION -v --version -- 'バージョン情報を表示して終了する'

	msg -- '' 'Exit Status:' \
		'    0 - successful termination' \
		'   64 - command line usage error' \
		'   65 - data format error' \
		'   66 - cannot open input' \
		'   67 - addressee unknown' \
		'   68 - host name unknown' \
		'   69 - service unavailable' \
		'   70 - internal software error' \
		"   71 - system error (e.g., can't fork)" \
		'   72 - critical OS file missing' \
		"   73 - can't create (user) output file" \
		'   74 - input/output error' \
		'   75 - temp failure; user is invited to retry' \
		'   76 - remote error in protocol' \
		'   77 - permission denied' \
		'   78 - configuration error' \
		'  129 - received SIGHUP' \
		'  130 - received SIGINT' \
		'  131 - received SIGQUIT' \
		'  143 - received SIGTERM'
}
# @end

# @gengetoptions parser -i parser_definition parse "${1}"
# @end

eval "$(getoptions parser_definition parse "${0}")"
parse ${@+"${@}"}
eval "set -- ${REST}"

case "${#}" in '0')
	printf "%s: 引数が不足しています。\\n" "${0##*/}" >&2
	printf "詳細については '%s' を実行してください。\\n" "${0##*/} --help" >&2

	end_call "${EX_USAGE}"
esac

output="${1}"
shift

mkdir -p "${output}"

includeShellscript=$(
	cat <<-'__EOF__'
	BEGIN {
		for(i = 1; i < ARGC; i++) {
			read_file(ARGV[i])
		}
	}

	function pathto(file,  len,pathlist,i,result,tmp) {
		if(index(file, "/") != 0) {
			return file
		}

		len = split(ENVIRON["PATH"], pathlist, ":")

		for(i = 1; i <= len; i++) {
			result = (pathlist[i] == "" ? "." : pathlist[i]) "/" file

			if(0 < (getline tmp < result)) {
				close(result)
				return result
			}
		}

		return ""
	}

	function read_file(file,  record,fields) {
		while(0 < (getline record < file)) {
			split(record, fields)

			if(fields[1] == ".") {
				gsub(/["']/, "", fields[2])
				fpath = pathto(fields[2])

				if(fpath == "") {
					printf("awk: %s: cannot find %s\n", file, fields[2]) | "cat >&2"
					exit
				}

				read_file(fpath)
			} else {
				printf("%s\n", record)
			}
		}

		close(file)
	}
	__EOF__
)

includeAwkscript=$(
	cat <<-'__EOF__'
	BEGIN {
		split("", include)

		for(i = 1; i < ARGC; i++) {
			read_file(ARGV[i], include)
		}
	}

	function pathto(file,  len,pathlist,i,result,tmp) {
		if(index(file, "/") != 0) {
			return file
		}

		len = split(ENVIRON["AWKPATH"], pathlist, ":")

		for(i = 1; i <= len; i++) {
			result = (pathlist[i] == "" ? "." : pathlist[i]) "/" file

			if(0 < (getline tmp < result)) {
				close(result)
				return result
			}
		}

		return ""
	}

	function read_file(file, include,  record,fields) {
		include[file] = 1

		while(0 < (getline record < file)) {
			split(record, fields)

			if(fields[1] == "@include") {
				gsub(/"/, "", fields[2])
				fpath = pathto(fields[2])

				if(fpath == "") {
					printf("awk: %s: cannot find %s\n", file, fields[2]) | "cat >&2"
					exit
				}

				if(!(fpath in include)) {
					read_file(fpath, include)
				}
			} else if(fields[1] == "__EOF__" || fields[1] == "'") {
				split("", include)
				printf("%s\n", record)
			} else {
				printf("%s\n", record)
			}
		}

		close(file)
	}
	__EOF__
)

for file in ${@+"${@}"}; do
	case "${verbose}" in '1')
		printf "Converting '%s'...\\n" "${file}" >&2
	esac

	if [ '!' -f "${file}" ]; then
		printf "%s: '%s' は通常ファイルではありません。\\n" "${0##*/}" "${file}" >&2
		continue
	elif [ '!' -r "${file}" ]; then
		printf "%s: '%s' の読み込み許可がありません。\\n" "${0##*/}" "${file}" >&2
		continue
	fi

	gengetoptions embed "${file}" \
	| sed -e '/eval .*getoptions/{ s/^/#/; }' \
	| awk -- "${includeShellscript}" - \
	| awk -- "${includeAwkscript}" - \
	| shfmt -s -ln 'posix' \
	| sed -e '1b; /^[[:blank:]]*#/d' >"${output}/${file##*/}"

	case "${verbose}" in '1')
		printf 'Done\n' >&2
	esac
done
