#!/usr/bin/env sh

### Script: uricheck
##
## URI を検証する。
##
## Metadata:
##
##   id - e1264d65-161a-4eb2-a8e4-072eafa05b62
##   author - <qq542vev at https://purl.org/meta/me/>
##   version - 1.3.2
##   date - 2022-10-12
##   since - 2020-02-21
##   copyright - Copyright (C) 2020-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:
##   uricheck [OPTION]... [URI]...
##   uricheck -V [OPTION]... [NOT_URI]...
##
## Options:
##   -f,     --field original | scheme[!] | authority[!] | userinfo[!] | host | port[!] | path | query[!] | fragment[!] 
##                               表示する URI のフィールドを指定する
##   -n,     --{no-}normalize    URI の正規化を行う
##   -V,     --{no-}invert       URI ではない引数を表示する
##           --{no-}verbose      詳細な表示を行う
##   -h,     --help              このヘルプを表示して終了する
##   -v,     --version           バージョン情報を表示して終了する
##
## Exit Status:
##     0 - successful termination
##     1 - not URI
##    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=uricheck 1.3.2'

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

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

	param field         -f --field          init:='original' validate:validate_field var:'original | scheme[!] | authority[!] | userinfo[!] | host | port[!] | path | query[!] | fragment[!]' -- '表示する URI のフィールドを指定する'
	flag  normalizeFlag -n --{no-}normalize init:@no -- 'URI の正規化を行う'
	flag  invertFlag    -V --{no-}invert    init:@no -- 'URI ではない引数を表示する'
	flag  verboseFlag   --{no-}verbose      init:@no -- '詳細な表示を行う'
	disp  :usage        -h --help    -- 'このヘルプを表示して終了する'
	disp  VERSION       -v --version -- 'バージョン情報を表示して終了する'

	msg -- '' 'Exit Status:' \
		'    0 - successful termination' \
		'    1 - not URI' \
		'   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

validate_field() {
	case "${OPTARG}" in '')
		return '0'
	esac

	set -- '(original|scheme!?|authority!?|userinfo!?|host|port!?|path|query!?|fragment!?)'
	regex_match "${OPTARG}" "^${1}(,${1})*$"
}

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

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

awkScript=$(
	cat <<-'__EOF__'
	@include "uri_check.awk"
	@include "url_encode_normalize.awk"
	@include "uri_path_remove_dot_segments.awk"
	@include "uri_parse.awk"

	BEGIN {
		fieldCount = split(field, fields, ",")
		exitStatus = 0

		for(i = 1; i < ARGC; i++) {
			uri = ARGV[i]

			if(uri_check(uri)) {
				if(normalizeFlag) {
					uri = url_encode_normalize(uri)
				}

				if(invertFlag) {
					exitStatus = 1

					if(verboseFlag) {
						printf("URI: %s\n", uri) | "cat >&2"
					}
				} else {
					uri_parse(uri, element)

					if(normalizeFlag) {
						element["path"] = uri_path_remove_dot_segments(element["path"])
					}

					for(fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) {
						if(fields[fieldIndex] == "original") {
							printf("%s", element["scheme"] element["authority"] element["path"] element["query"] element["fragment"])
						} else if(fields[fieldIndex] == "scheme") {
							printf("%s", substr(element["scheme"], 1, length(element["scheme"]) - 1))
						} else if(fields[fieldIndex] == "scheme!") {
							printf("%s", element["scheme"])
						} else if(fields[fieldIndex] == "authority") {
							printf("%s", substr(element["authority"], 3))
						} else if(fields[fieldIndex] == "authority!") {
							printf("%s", element["authority"])
						} else if(fields[fieldIndex] == "userinfo") {
							printf("%s", substr(element["userinfo"], 1, length(element["userinfo"]) - 1))
						} else if(fields[fieldIndex] == "userinfo!") {
							printf("%s", element["userinfo"])
						} else if(fields[fieldIndex] == "host") {
							printf("%s", element["host"])
						} else if(fields[fieldIndex] == "port") {
							printf("%s", substr(element["port"], 2))
						} else if(fields[fieldIndex] == "port!") {
							printf("%s", element["port"])
						} else if(fields[fieldIndex] == "path") {
							printf("%s", element["path"])
						} else if(fields[fieldIndex] == "query") {
							printf("%s", substr(element[query], 2))
						} else if(fields[fieldIndex] == "query!") {
							printf("%s", element["query"])
						} else if(fields[fieldIndex] == "fragment") {
							printf("%s", substr(element["fragment"], 2))
						} else if(fields[fieldIndex] == "fragment!") {
							printf("%s", element["fragment"])
						}

						printf(fieldIndex == fieldCount ? "\n" : "\t")
					}
				}
			} else {
				if(invertFlag) {
					printf("%s\n", uri)
				} else {
					exitStatus = 1

					if(verboseFlag) {
						printf("not URI: %s\n", uri) | "cat >&2"
					}
				}
			}
		}

		exit exitStatus
	}
	__EOF__
)

awk \
	-v "field=${field}" \
	-v "normalizeFlag=${normalizeFlag}" \
	-v "invertFlag=${invertFlag}" \
	-v "verboseFlag=${verboseFlag}" \
	-- "${awkScript}" \
	${@+"${@}"} \
|| end_call "${?}"
