# Copyright (c) 2017 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Johnny C. Lam.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# NAME
#	info_files.subr -- GNU info file management for packages
#
# SYNOPSIS
#	task_info_files [-s] add | remove
#
# DESCRIPTION
#	The task_info_files function supports two actions, "add" and
#	"remove", that will add or remove entries from GNU info files
#	from index files (the "dir" file in the same diretory as the info
#	files).
#
#	The available options are as follows:
#
#	-s	Silent; don't write to standard output.
#
#	The task_info_files function reads standard input line by line and
#	looks for lines of the form:
#
#	    # INFO: <file> [<infodir>]
#
#	If any of the paths to the file or infodir are relative, then they
#	are assumed to be relative to ${PKG_PREFIX}.
#
# RETURN VALUES
#	Returns 0 if the action is successful for all info files, and >0
#	if an error occurs.
#
# ENVIRONMENT
#	The following variables are used if they are set:
#
#	INSTALL_INFO
#		The name or path to the install-info(1) utility that can
#		add or remove GNU info files from index files.
#
#	PKGNAME
#		The name of the package.
#
#	PKG_DESTDIR
#		A "destdir" prefix that is prepended to all filesystem
#		paths.  The default value is the empty string.
#
#	PKG_PREFIX
#		The installation prefix of the package.  The default is
#		"/usr/pkg".
#
#	RM	The name or path to the rm(1) utility.
#
#	RMDIR	The name or path to the rmdir(1) utility.
#
#	TASK_MSG
#		String prepended to all normal message written to
#		standard output.
#

__task_info_files__="yes"
__task_info_files_init__="_task_info_files_init"

task_load cleanup
task_load echo
task_load makedir
task_load match
task_load quote

task_info_files()
{
	: ${INSTALL_INFO:=install-info}
	: ${RM:=rm}
	: ${RMDIR:=rmdir}

	: ${PKG_PREFIX:=/usr/pkg}
	: ${PKGNAME:=${0##*/}}
	: ${TASK_MSG:=""}

	local arg
	local echo="task_echo"
	local silent=
	local OPTIND=1
	while getopts ":s" arg "$@"; do
		case $arg in
		s)	echo=":"; silent="-s" ;;
		*)	return 127 ;;
		esac
	done
	shift $(( ${OPTIND} - 1 ))
	[ $# -gt 0 ] || return 127

	local action="$1"; shift
	case $action in
	add|remove)
		: "valid action" ;;
	*)	return 0 ;;
	esac

	# Guard against ${PKG_PREFIX} == "/".
	local prefix
	case ${PKG_PREFIX}/ in
	//)	prefix= ;;
	*)	prefix=${PKG_PREFIX} ;;
	esac

	local result line_result
	local index quoted

	result=0
	local hash tag file infodir
	while read hash tag file infodir; do
		# Filter for "# INFO:"
		case $hash/$tag in
		"#/INFO:")
			: "use this line" ;;
		*)	continue ;;
		esac

		# Canonicalize paths.
		case $file in
		"")	# skip lines without required args
			continue ;;
		[!/]*)	file="$prefix/$file" ;;
		esac
		file="${PKG_DESTDIR}$file"
		case $infodir in
		"")	infodir=${file%/*} ;;
		[!/]*)	infodir="$prefix/$infodir" ;;
		esac
		infodir="${PKG_DESTDIR}$infodir"

		if [ ! -f "$file" ]; then
			$echo "${TASK_MSG}! info file missing: $file"
			result=1
			continue
		fi

		index="$infodir/dir"
		task_quote "$index"
		__task_info_files_indices__="$__task_info_files_indices__ $quoted"

		line_result=0
		case $action in
		add)	# Remove any existing file entry from the "dir" file
			# to guard against a duplicate entry when we add later.
			# Suppress the output since we don't care if the removal
			# was successful or not.
			#
			${INSTALL_INFO} --info-dir="$infodir" --delete "$file" >/dev/null 2>&1
			# Add the file entry to the "dir" file.
			[ -d "$infodir" ] || task_makedir "$infodir" 2>/dev/null
			[ -d "$infodir" ] || line_result=1
			if [ $line_result -eq 0 ]; then
				${INSTALL_INFO} --info-dir="$infodir" "$file" || line_result=1
			fi
			if [ $line_result -eq 0 ]; then
				$echo "${TASK_MSG}> info file registered: $file"
			else
				$echo "${TASK_MSG}! info file not registered: $file"
			fi ;;
		remove)	if [ -f "$index" ]; then
				${INSTALL_INFO} --info-dir="$infodir" --delete "$file" || line_result=1
				if [ $line_result -eq 0 ]; then
					$echo "${TASK_MSG}> info file unregistered: $file"
				else
					$echo "${TASK_MSG}! info file not unregistered: $file"
				fi
			else
				$echo "${TASK_MSG}> info file already unregistered: $file"
			fi ;;
		esac
		[ $line_result -eq 0 ] || result=1
	done

	_task_info_files_cleanup $silent
	return $result
}

_task_info_files_cleanup()
{
	: ${RM:=rm}
	: ${RMDIR:=rmdir}

	: ${TASK_MSG:=""}

	local arg
	local echo="task_echo"
	local OPTIND=1
	while getopts ":s" arg "$@"; do
		case $arg in
		s)	echo=":" ;;
		*)	return 127 ;;
		esac
	done
	shift $(( ${OPTIND} - 1 ))

	# Guard against ${PKG_PREFIX} == "/".
	local prefix
	eval set -- $__task_info_files_indices__
	local index
	for index; do
		[ -f "$index" ] || continue
		#
		# Check if the "dir" file has any entries and
		# remove it if it doesn't.
		#
		if task_match -v "[*][ 	][mM]enu:*" < $index |
		   task_match -q '[*][ 	]*'; then
			: "entries exist"
		else
			${RM} -f "$index"
			${RMDIR} -p "${index%/*}" 2>/dev/null
			$echo "${TASK_MSG}> empty dir file removed: $index"
		fi
	done
	__task_info_files_indices__=
}

_task_info_files_init()
{
	task_cleanup_add_hook _task_info_files_cleanup
}

# Static variable for "dir" indices that should be removed if empty if an
# error occurs.
#
__task_info_files_indices__=
