#!/usr/bin/env sh


readonly 'VERSION=pushuri 4.0.2'



set -efu
umask '0022'
readonly "LC_ALL_ORG=${LC_ALL-}"
LC_ALL='C'
IFS=$(printf ' \t\n_')
IFS="${IFS%_}"
PATH="${PATH-}${PATH:+:}$(command -p getconf 'PATH')"
UNIX_STD='2003'         # HP-UX POSIX mode
XPG_SUS_ENV='ON'        # AIX POSIX mode
XPG_UNIX98='OFF'        # AIX UNIX 03 mode
POSIXLY_CORRECT='1'     # GNU Coreutils POSIX mode
COMMAND_MODE='unix2003' # macOS UNIX 03 mode
export 'LC_ALL' 'IFS' 'PATH' 'UNIX_STD' 'XPG_SUS_ENV' 'XPG_UNIX98' 'POSIXLY_CORRECT' 'COMMAND_MODE'




readonly 'EX_OK=0' # successful termination

readonly 'EX__BASE=64' # base value for error messages

readonly 'EX_USAGE=64'       # command line usage error
readonly 'EX_DATAERR=65'     # data format error
readonly 'EX_NOINPUT=66'     # cannot open input
readonly 'EX_NOUSER=67'      # addressee unknown
readonly 'EX_NOHOST=68'      # host name unknown
readonly 'EX_UNAVAILABLE=69' # service unavailable
readonly 'EX_SOFTWARE=70'    # internal software error
readonly 'EX_OSERR=71'       # system error (e.g., can't fork)
readonly 'EX_OSFILE=72'      # critical OS file missing
readonly 'EX_CANTCREAT=73'   # can't create (user) output file
readonly 'EX_IOERR=74'       # input/output error
readonly 'EX_TEMPFAIL=75'    # temp failure; user is invited to retry
readonly 'EX_PROTOCOL=76'    # remote error in protocol
readonly 'EX_NOPERM=77'      # permission denied
readonly 'EX_CONFIG=78'      # configuration error

readonly 'EX__MAX=78' # maximum listed value

trap 'case "${?}" in 0) end_call;; *) end_call "${EX_SOFTWARE}";; esac' 0 # EXIT
trap 'end_call 129' 1                                                     # SIGHUP
trap 'end_call 130' 2                                                     # SIGINT
trap 'end_call 131' 3                                                     # SIGQUIT
trap 'end_call 143' 15                                                    # SIGTERM

alias org_lc='LC_ALL="${LC_ALL_ORG}"'


end_call() {
	trap '' 0 # EXIT
	rm -fr -- ${tmpDir:+"${tmpDir}"}
	exit "${1:-0}"
}



option_error() {
	printf '%s: %s\n' "${0##*/}" "${1}" >&2
	printf "詳細については '%s' を実行してください。\\n" "${0##*/} --help" >&2

	end_call "${EX_USAGE}"
}



regex_match() {
	awk -- '
		BEGIN {
			for(i = 2; i < ARGC; i++) {
				if(ARGV[1] !~ ARGV[i]) {
					exit 1
				}
			}

			exit
		}
	' ${@+"${@}"} || return 1

	return 0
}

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

	param config -c --config init:'config="${HOME}/.w3mplus/tabrestore"' var:FILE -- '設定ファイルを指定する'
	param :'eval "${1#--}=\"\${OPTARG}\""' --c1 --c2 --c3 --c4 --c5 --c6 --c7 --c8 --c9 validate:'regex_match "${OPTARG}" "^-?[1-9][0-9]*$"' var:'[-]COLUMN_NUMBER' -- 'n個目の URI に対応する列番号を指定する'
	param :'eval "${1#--}=\"\${OPTARG}\""' --l1 --l2 --l3 --l4 --l5 --l6 --l7 --l8 --l9 validate:'regex_match "${OPTARG}" "^-?[1-9][0-9]*$"' var:'[-]LINE_NUMBER' -- 'n個目の URI に対応する行番号を指定する'
	param size -s --size init:='50000' validate:'regex_match "${OPTARG}" "^(0|[1-9][0-9]*)$"' var:UNSIGNED_INTEGER -- 'URI の履歴数を指定する'
	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'
}

config="${HOME}/.w3mplus/tabrestore"
size='50000'
REST=''
parse() {
	OPTIND=$(($# + 1))
	while OPTARG= && [ $# -gt 0 ]; do
		set -- "${1%%\=*}" "${1#*\=}" "$@"
		while [ ${#1} -gt 2 ]; do
			case $1 in *[!a-zA-Z0-9_-]*) break ;; esac
			case '--config' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --config" ;;
			esac
			case '--c1' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c1" ;;
			esac
			case '--c2' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c2" ;;
			esac
			case '--c3' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c3" ;;
			esac
			case '--c4' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c4" ;;
			esac
			case '--c5' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c5" ;;
			esac
			case '--c6' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c6" ;;
			esac
			case '--c7' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c7" ;;
			esac
			case '--c8' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c8" ;;
			esac
			case '--c9' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --c9" ;;
			esac
			case '--l1' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l1" ;;
			esac
			case '--l2' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l2" ;;
			esac
			case '--l3' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l3" ;;
			esac
			case '--l4' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l4" ;;
			esac
			case '--l5' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l5" ;;
			esac
			case '--l6' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l6" ;;
			esac
			case '--l7' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l7" ;;
			esac
			case '--l8' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l8" ;;
			esac
			case '--l9' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --l9" ;;
			esac
			case '--size' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --size" ;;
			esac
			case '--help' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --help" ;;
			esac
			case '--version' in
			"$1")
				OPTARG=
				break
				;;
			$1*) OPTARG="$OPTARG --version" ;;
			esac
			break
		done
		case ${OPTARG# } in
		*\ *)
			eval "set -- $OPTARG $1 $OPTARG"
			OPTIND=$((($# + 1) / 2)) OPTARG=$1
			shift
			while [ $# -gt "$OPTIND" ]; do
				OPTARG="$OPTARG, $1"
				shift
			done
			set "Ambiguous option: $1 (could be $OPTARG)" ambiguous "$@"
			option_error "$@" >&2 || exit $?
			echo "$1" >&2
			exit 1
			;;
		?*)
			[ "$2" = "$3" ] || OPTARG="$OPTARG=$2"
			shift 3
			eval 'set -- "${OPTARG# }"' ${1+'"$@"'}
			OPTARG=
			;;
		*) shift 2 ;;
		esac
		case $1 in
		--?*=*)
			OPTARG=$1
			shift
			eval 'set -- "${OPTARG%%\=*}" "${OPTARG#*\=}"' ${1+'"$@"'}
			;;
		--no-* | --without-*) unset OPTARG ;;
		-[cs]?*)
			OPTARG=$1
			shift
			eval 'set -- "${OPTARG%"${OPTARG#??}"}" "${OPTARG#??}"' ${1+'"$@"'}
			;;
		-[hv]?*)
			OPTARG=$1
			shift
			eval 'set -- "${OPTARG%"${OPTARG#??}"}" -"${OPTARG#??}"' ${1+'"$@"'}
			OPTARG=
			;;
		+*) unset OPTARG ;;
		esac
		case $1 in
		'-c' | '--config')
			[ $# -le 1 ] && set "required" "$1" && break
			OPTARG=$2
			config="$OPTARG"
			shift
			;;
		'--c1' | '--c2' | '--c3' | '--c4' | '--c5' | '--c6' | '--c7' | '--c8' | '--c9')
			[ $# -le 1 ] && set "required" "$1" && break
			OPTARG=$2
			regex_match "${OPTARG}" "^-?[1-9][0-9]*$" || {
				set -- regex_match:$? "$1" regex_match "${OPTARG}" "^-?[1-9][0-9]*$"
				break
			}
			eval "${1#--}=\"\${OPTARG}\""
			shift
			;;
		'--l1' | '--l2' | '--l3' | '--l4' | '--l5' | '--l6' | '--l7' | '--l8' | '--l9')
			[ $# -le 1 ] && set "required" "$1" && break
			OPTARG=$2
			regex_match "${OPTARG}" "^-?[1-9][0-9]*$" || {
				set -- regex_match:$? "$1" regex_match "${OPTARG}" "^-?[1-9][0-9]*$"
				break
			}
			eval "${1#--}=\"\${OPTARG}\""
			shift
			;;
		'-s' | '--size')
			[ $# -le 1 ] && set "required" "$1" && break
			OPTARG=$2
			regex_match "${OPTARG}" "^(0|[1-9][0-9]*)$" || {
				set -- regex_match:$? "$1" regex_match "${OPTARG}" "^(0|[1-9][0-9]*)$"
				break
			}
			size="$OPTARG"
			shift
			;;
		'-h' | '--help')
			usage
			exit 0
			;;
		'-v' | '--version')
			echo "${VERSION}"
			exit 0
			;;
		--)
			shift
			while [ $# -gt 0 ]; do
				REST="${REST} \"\${$((OPTIND - $#))}\""
				shift
			done
			break
			;;
		[-+]?*)
			set "unknown" "$1"
			break
			;;
		*)
			REST="${REST} \"\${$((OPTIND - $#))}\""
			;;
		esac
		shift
	done
	[ $# -eq 0 ] && {
		OPTIND=1
		unset OPTARG
		return 0
	}
	case $1 in
	unknown) set "Unrecognized option: $2" "$@" ;;
	noarg) set "Does not allow an argument: $2" "$@" ;;
	required) set "Requires an argument: $2" "$@" ;;
	pattern:*) set "Does not match the pattern (${1#*:}): $2" "$@" ;;
	notcmd) set "Not a command: $2" "$@" ;;
	*) set "Validation error ($1): $2" "$@" ;;
	esac
	option_error "$@" >&2 || exit $?
	echo "$1" >&2
	exit 1
}
usage() {
	cat <<'GETOPTIONSHERE'
Usage:
  pushuri [OPTION]... [URI]...

Options:
  -c,     --config FILE       設定ファイルを指定する
          --c1, --c2, --c3, --c4, --c5, --c6, --c7, --c8, --c9 [-]COLUMN_NUMBER 
                              n個目の URI に対応する列番号を指定する
          --l1, --l2, --l3, --l4, --l5, --l6, --l7, --l8, --l9 [-]LINE_NUMBER 
                              n個目の URI に対応する行番号を指定する
  -s,     --size UNSIGNED_INTEGER 
                              URI の履歴数を指定する
  -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
GETOPTIONSHERE
}

parse ${@+"${@}"}
eval "set -- ${REST}"

tmpDir=$(mktemp -d)
unixtime=$(date -u -- '+%Y%m%d%H%M%S' | TZ='UTC+0' utconv)
awkScript=$(
	cat <<-'__EOF__'





		function array_length(array,  count,key) {
			count = 0

			for(key in array) {
				count++
			}

			return count
		}


		function array_print(array, start, end, separator, format,  result) {
			if(start == "") {
				start = 1
			}

			if(end == "") {
				end = array_length(array)
			}

			if(format == "") {
				format = "%s"
			}

			for(result = ""; start <= end; start++) {
				if(start in array) {
					result = result separator sprintf(format, array[start])
				}
			}

			return substr(result, length(separator) + 1)
		}

			BEGIN {
				previousCount = split("", previous)
			}

			$1 != previous[1] && previous[1] != "" {
				printf("%s\n", array_print(previous, 1, previousCount, "\t"))
			}

			{
				previousCount = split($0, previous)
			}

			END {
				printf("%s\n", array_print(previous, 1, previousCount, "\t"))
			}
	__EOF__
)

if [ '!' -e "${config}" ]; then
	configDir=$(
		dirname -- "${config}"
		printf '_'
	)
	mkdir -p -- "${configDir%?_}"

	: >"${config}"
fi

if [ '!' -f "${config}" ]; then
	printf "%s: '%s' は通常ファイルではありません。\\n" "${0##*/}" "${config}" >&2
	printf "詳細については '%s' を実行してください。\\n" "${0##*/} --help" >&2

	end_call "${EX_DATAERR}"
elif [ '!' -r "${config}" ]; then
	printf "%s: '%s' の読み込み許可がありません。\\n" "${0##*/}" "${config}" >&2
	printf "詳細については '%s' を実行してください。\\n" "${0##*/} --help" >&2

	end_call "${EX_NOINPUT}"
fi

org_lc uricheck --field '' --verbose -- ${@+"${@}"} || end_call "${EX_USAGE}"

{
	cat -- "${config}"

	for uri in ${@+"${@}"}; do
		i=$((${i-0} + 1))

		eval "colmun=\${c${i}:-1}"
		eval "line=\${l${i}:-1}"

		printf '%s\t%d\t%d\t%s\n' "${uri}" "${line}" "${colmun}" "${unixtime}"
	done
} | awk -- "${awkScript}" | tail -n "${size}" >"${tmpDir}/file"

cat -- "${tmpDir}/file" >"${config}"
