#!/bin/sh -e
# ==================================================================================
# portsreinstall main script
# Copyright (C) 2010-2012 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
# This software is distributed under the 2-Clause BSD License.
# ==================================================================================

# ================================================
# ================ PREPARATION ===================
# ================================================

APPNAME=`basename "$0"`
MYVERSION=2.1.0

PREFIX=${PREFIX:-/usr/local}
CONFFILE=${PREFIX}/etc/${APPNAME}.conf
DBDIR=/var/tmp/${APPNAME}.db
PKGTOOLSCONF=${PREFIX}/etc/pkgtools.conf

# ============= Creation of temporary work directories =============
terminate_process ()
{
}
warn_update_ports ()
{
}
{ until TMPDIR=`mktemp -dq /tmp/"${APPNAME}".XXXXXX 2> /dev/null` ; do : ; done ; }
trap 'errno=$?; warn_update_ports; terminate_process; rm -r'`[ \`uname -s\` = FreeBSD ] && echo -n P`' "${TMPDIR}" 2> /dev/null; [ $errno -gt 0 -a $errno -ne 130 ] && echo "(Error exit by $errno)" >&2; exit $errno' 0 1 2 3 9 15 17 18

# ============= Save arguments for updated restart =============
restart_command ()
{
	echo -n "exec `echo "$0" | sed -E 's/(.)/\\\\\\1/g'`"
	while [ $# -ge 1 ]
	do
		echo -n " `echo "$1" | sed -E 's/(.)/\\\\\\1/g'`"
		shift
	done
}
restart_command "$@" > ${TMPDIR}/restart_command.sh

# ============= Option check =============
help_mode=0
option_err=0
target_dependent_ports=
target_required_ports=
target_dependent_ports_form2=
target_required_ports_form2=
taboo_ports=
taboo_ports_form2=
load_pkgtoolsconf=undef
show_version=no
avoid_vulner=no
skip_unchanged=no
keep_distfiles=no
renew_options=no
supress_self_upadte=no
supress_obsolete_db_clean=no
while :
do
	if [ "$1" = "-h" ]
	then
		help_mode=1
		shift
	elif [ "$1" = "-H" ]
	then
		help_mode=2
		shift
	elif [ "$1" = "-t" ]
	then
		target_dependent_ports=$target_dependent_ports,$2
		shift 2
	elif [ "$1" = "-T" ]
	then
		target_required_ports=$target_required_ports,$2
		shift 2
	elif [ "$1" = "-r" ]
	then
		target_dependent_ports_form2="$target_dependent_ports_form2 $2"
		shift 2
	elif [ "$1" = "-R" ]
	then
		target_required_ports_form2="$target_required_ports_form2 $2"
		shift 2
	elif [ "$1" = "-x" ]
	then
		taboo_ports=$taboo_ports,$2
		shift 2
	elif [ "$1" = "-X" ]
	then
		taboo_ports_form2="$taboo_ports_form2 $2"
		shift 2
	elif [ "$1" = "-p" ]
	then
		load_pkgtoolsconf=default
		shift
	elif [ "$1" = "-P" ]
	then
		load_pkgtoolsconf=override
		shift
	elif [ "$1" = "-Q" ]
	then
		load_pkgtoolsconf=no
		shift
	elif [ "$1" = "-V" ]
	then
		show_version=yes
		shift
	elif [ "$1" = "-s" ]
	then
		avoid_vulner=yes
		shift
	elif [ "$1" = "-q" ]
	then
		skip_unchanged=yes
		shift
	elif [ "$1" = "-d" ]
	then
		keep_distfiles=yes
		shift
	elif [ "$1" = "-N" ]
	then
		renew_options=yes
		shift
	elif [ "$1" = "-k" ]
	then
		supress_self_upadte=yes
		shift
	elif [ "$1" = "-c" ]
	then
		supress_obsolete_db_clean=yes
		shift
	else
		break
	fi
done

# if [ $# -gt 0 ]
# then
# 	option_err=1
# fi

credit ()
{
	echo "${APPNAME} version ${MYVERSION}"
	echo " -- Ports upgrading utility for massive forced reinstallation"
	echo " -- And for those who are pursuing the perfect packages environment"
	echo "Copyright (C) 2010 - 2012 Mamoru Sakaue, MwGhennndo, All Rights Reserved."
	echo "Email: <sakaue.mamoru@samurai.mwghennn.net>"
	echo "Homepage: <http://www.mwghennndo.com/softwares/portsreinstall/>"
}

# Usage
if [ $help_mode -eq 1 -o $option_err -eq 1 ]
then
	echo "USAGE: ${APPNAME} [OPTIONS] [command]"
	echo
	echo "[OPTIONS]"
	echo " -h : Show this short help."
	echo " -H : Show long help."
	echo " -V : Show the current version."
	echo " -t glob1[,glob2,...] : Reinstall only target ports and their dependents."
	echo " -r glob : Reinstall only the target port and their dependents."
	echo " -T glob1[,glob2,...] : Reinstall only target ports and their requirements."
	echo " -R glob : Reinstall only target ports and their requirements."
	echo " -x glob1[,glob2,...] : Set the port glob(s) to be taboo."
	echo " -X glob : Set a port glob to be taboo."
	echo " -p : Import settings from pkgtools.conf(5) as the primary if exists (default)."
	echo " -P : Import settings from pkgtools.conf(5) as the secondary if exists."
	echo " -Q : Ignore pkgtools.conf(5) even if it exists."
	echo " -s : Build of vulnerable ports are avoided by triggering errors."
	echo " -q : Ports whose all requirements and themselves are not new are skipped."
	echo " -d : Do not clean up obsolete or unused distfiles."
	echo " -N : Renew option settings (only for redo command)."
	echo " -k : Keep ${APPNAME} itself untouched."
	echo " -c : Suppress cleaning the temporal database even if its obsolete."
	echo
	echo "[ARGUMENTS]"
	echo " command: do (default) | prepare | redo | clean | ok add globs..."
	echo "          | ok del globs... | taboo add globs... | taboo del globs..."
	echo "          | save [dir] | load path"
	echo "          | show todo | show done | show resolved | show failure | show taboo"
	echo "          | show deleted | show requirements glob... | show dependents glob..."
	echo
	echo "[DESCRIPTIONS]"
	echo " This utility is an alternative to portupgrade(1) and portmaster(8), and"
	echo "designed to be suitable for reinstallation of all packages after major version"
	echo "upgrade of the system or very long absence of ports upgrade."
	echo " Usually, you can execute with no option nor argument. If portupgrade(1) is"
	echo "installed, compatibility with it is taken into account by importing"
	echo "pkgtools.conf(5) and rebuilding the package database."
	exit $option_err
elif [ $help_mode -eq 2 ]
then
	credit
	echo
	echo "USAGE: ${APPNAME} [OPTIONS] [command]"
	echo
	echo "[OPTIONS]"
	echo " -h : Show short help."
	echo " -H : Show this long help."
	echo " -V : Show the current version."
	echo " -t glob1[,glob2,...] : Reinstall only target ports and their dependents."
	echo "        Target ports which are not installed yet are newly installed."
	echo "        Target ports which are obsolete are deinstalled."
	echo "        This option can be given multiply."
	echo "        This option is recognized in the first 'do' or 'redo' runs, and"
	echo "        transferred to the restarted runs."
	echo "        Dependency relations are inspected for all installed packages as well."
	echo "        Combination with options '-T', '-r' and '-R' is available."
	echo " -r glob : Reinstall only the target port and their dependents."
	echo "        This option can be given multiply."
	echo "        The difference from '-t' is that only one port glob can be specified."
	echo "        Thus a package name with commas is available."
	echo "        Combination with options '-t', '-T' and '-R' is available."
	echo " -T glob1[,glob2,...] : Reinstall only target ports and their requirements."
	echo "        Target ports which are not installed yet are newly installed."
	echo "        Target ports which are obsolete are deinstalled."
	echo "        This option can be given multiply."
	echo "        This option is recognized in the first 'do' or 'redo' runs, and"
	echo "        transferred to the restarted runs."
	echo "        Dependency relations are inspected for all installed packages as well."
	echo "        Combination with options '-t', '-r' and '-R' is available."
	echo " -R glob : Reinstall only target ports and their requirements."
	echo "        This option can be given multiply."
	echo "        The difference from '-T' is that only one port glob can be specified."
	echo "        Thus a package name with commas is available."
	echo "        Combination with options '-t', '-r' and '-T' is available."
	echo " -x glob1[,glob2,...] : Set the port glob(s) to be taboo."
	echo "        This option registers a port to be ignored as taboo."
	echo "        This option can be given multiply."
	echo "        Mainly for ports that show terrible behaviors resulting in system crash."
	echo "        This option is recognized in the first 'do' or 'redo' runs, and"
	echo "        transferred to the restarted runs."
	echo "        Alternatively you can do the same thing by 'taboo' command."
	echo "        If you want to register permanently, set to the configuration file."
	echo "        Combination with options '-X' is available."
	echo " -X glob : Set a port glob to be taboo."
	echo "        This option can be given multiply."
	echo "        The difference from '-x' is that only one port glob can be specified."
	echo "        Thus a package name with commas is available."
	echo "        Combination with options '-x' is available."
	echo " -p : Import settings from pkgtools.conf(5) as the primary."
	echo "        For duplicated configurations, values in pkgtools.conf are applied"
	echo "        first and then those in ${APPNAME}.conf are."
	echo "        This option is ignored when you restart a terminated process."
	echo "        (Default; ignored if ports-mgmt/portupgrade* is not installed)"
	echo " -P : Import settings from pkgtools.conf(5) as the secondary."
	echo "        For duplicated configurations, values in ${APPNAME}.conf are applied"
	echo "        first and then those in pkgtools.conf are."
	echo "        This option is ignored when you restart a terminated process."
	echo "        (Ignored if ports-mgmt/portupgrade* is not installed)"
	echo " -Q : Ignore pkgtools.conf(5) even if it exists."
	echo "        This option is ignored when you restart a terminated process."
	echo " -s : Build of vulnerable ports are avoided by triggering errors."
	echo "        Note that already installed vulnerable packages are untouched."
	echo "        If you desire to uninstall them, do it manually."
	echo "        This specification will be reasonable for the practical situations."
	echo "        This option is fixed at the first 'do' run, and transferred to the"
	echo "        following runs."
	echo "        If you want to continue the reinstallation process by resetting"
	echo "        this option, execute by 'redo' command with '-N' option."
	echo " -q : Ports whose all requirements and themselves are not new are skipped."
	echo "        This option is safe and useful when the all of the major version of"
	echo "        the system, configuration options of each ports, pkgtools.conf(5),"
	echo "        ${APPNAME}.conf are unchanged."
	echo "        This option is fixed at the first 'do' run, and transferred to the"
	echo "        following runs."
	echo "        If you want to continue the reinstallation process by resetting"
	echo "        this option, execute by 'redo' command with '-N' option."
	echo " -d : Do not clean up obsolete or unused distfiles."
	echo "        This option is fixed at the first 'do' run, and transferred to the"
	echo "        following runs."
	echo "        If you want to continue the reinstallation process by resetting"
	echo "        this option, execute by 'redo' command with '-N' option."
	echo " -N : Renew option settings."
	echo "        This option is effective only with 'redo' command."
	echo "        Option settings for '-s', '-q' and '-d' are reset according to"
	echo "        the simultaneously given ones."
	echo " -k : Keep ${APPNAME} itself untouched."
	echo "        This option supresses update, deinstallation and reinstallation of"
	echo "        the currently installed ${APPNAME}."
	echo " -c : Suppress cleaning the temporal database even if its obsolete."
	echo "        By default, the temporal database is automatically cleaned up if"
	echo "        it is older than the ports tree or ${APPNAME} itself is to be"
	echo "        updated."
	echo "        This option replace this behavior with termination with warnings."
	echo "        This option should not be used unless the user has special"
	echo "        intentions."
	echo
	echo "[ARGUMENTS]"
	echo " command: (For optional operations or confirmation)"
	echo "      {one of the following commands}"
	echo "      do : full execution (default)"
	echo "      prepare : stop before the actual operations to the ports/packages"
	echo "      redo : execute again for failed ports and their dependents"
	echo "      clean : clean up the temporal database"
	echo "      ok add glob1 [glob2 ...] : register manually resolved ports"
	echo "      ok del glob1 [glob2 ...] : deregister manually resolved ports"
	echo "      taboo add glob1 [glob2 ...]: register taboo ports"
	echo "      taboo del glob1 [glob2 ...]: deregister taboo ports"
	echo "      save [dir] : save the current temporal database as a .tar.gz archive"
	echo "      load path : load a temporal database archive"
	echo "      show [args] : show the list of ports to be reinstalled"
	echo "            todo : ports to be reinstalled (default)"
	echo "            done : already reinstalled ports"
	echo "            resolved : manually reinstalled ports"
	echo "            failure : failed ports"
	echo "            taboo : taboo ports"
	echo "            deleted : obsolete ports to be or have been deleted"
	echo "            requirements glob1 [glob2 ...] : ports required by matching ports"
	echo "            dependents glob1 [glob2 ...] : ports depending on matching ports"
	echo
	echo "[CONFIGURATION FILE]"
	echo "          ${CONFFILE}"
	echo
	echo "[NOTATIONS]"
	echo " The 'glob' is either of pkgname_glob or portorigin_glob explained in the man"
	echo "page of portsdb(1) and ports_glob(1): for example, zip-3.0, zip-*, and archivers"
	echo "/zip. Here the wild card symbol '*' must be quoted or escaped. In evaluation of"
	echo "globs, ports_glob(1) is used if it is installed for better compatibility,"
	echo "otherwise an alternative internal function is used."
	echo
	echo "[DESCRIPTIONS]"
	echo " This utility realizes smart reinstallation of a large number of ports by"
	echo "allowing you to run when when the machine is free and terminate when busy."
	echo " Concretely, you can stop the process by CTRL+C anytime and restart quickly."
	echo " This functionality allows you, for example, to start this utility before lunch,"
	echo "terminate after lunch, restart before dinner, terminate after dinner, restart"
	echo "before going to bed, terminate after breakfast, restart before lunch, ..., and"
	echo "finally complete."
	echo
	echo " The policy of this utility is to complete the job by the most automatic and"
	echo "finally successful way even if it will take a long time in total."
	echo " All missing build- and run-time dependencies are newly installed if any."
	echo " All reinstallation processes are tried to be proceeded forcibly by ignoring"
	echo "errors or vulnerabilities as possible."
	echo " This utility pursues the consistency of the dependency relations in the latest"
	echo "version of the ports tree by on-the-fly entire reconstruction of the relations"
	echo "while portupgrade(1) and portmaster(8) believe the existing relations of the"
	echo "installed packages to reduce the total work time as much as possible."
	echo
	echo " In the simplest case, all a user has to do toward complete reinstallation is"
	echo "execute this utility without any arguments (corresponding to 'do' command). If"
	echo "the run completes with notations on failures for any ports, after resolving the"
	echo "errors manually, register the resolved ports by executing this utility with"
	echo "'ok add' command and then execute with 'redo' command. This task is continued"
	echo "until successful completion."
	echo
	echo " The algorithms of this utility are customized for massive reinstallation to"
	echo "be invoked after major upgrade of the system where rebuild of all third-party"
	echo "applications are encouraged before cleaning up obsolete system libraries."
	echo " Nevertheless, the all functionalities of this utility is applicable to any"
	echo "situations where complete reinstallation of the all or parts of ports is"
	echo "preferred, e.g., when you have been lazy in upgrade of ports for too long time."
	echo " For the usual purposes of upgrading packages installed by ports, you are"
	echo "recommended to use ports-mgmt/portupgrade or ports-mgmt/portmaster instead."
	echo
	echo " If this utility has been installed by ports/packages and the corresponding port"
	echo "is renewed, update of this utility is carried out first and then the following"
	echo "processes are continued by the new version after cleaning up the temporal"
	echo "database."
	echo
	echo " The scheme of this utility is divided into the temporal database construction"
	echo "phase and the reinstallation phase."
	echo " Execution by 'portsreinstall prepare' procedes to the end the first phase, and"
	echo "that without any argument procedes to the end of the second phase."
	echo " Each of these two major phases is divided into minor phases."
	echo " When the previously terminated process is restarted, completed minor phases are"
	echo "skipped.">&2
	echo
	echo " The massive minor phases belong to 'collecting dependencies of installed/"
	echo "missing packages', 'ordering dependencies' for the first major phase and"
	echo "'reinstallation' 'package database update' for the second."
	echo " Most of them are divided into more minor phases except for 'package database"
	echo "update'."
	echo
	echo " When option(s) '-t', '-r', '-T'  or '-R' is/are given in the first run of 'do'"
	echo "or 'redo' commands, only the targets and their required or dependent ports are"
	echo "reinstalled (or deleted if obsolete)."
	echo " This specification is effective until the completion of the run."
	echo " Run by 'redo' command without the options inherits the previous settings."
	echo " Meanwhile, run by 'redo' command with the options resets the previous settings,"
	echo "and inspects the dependencies again if new ports are to be installed."
	echo
	echo " The user is encouraged to run this utility under script(1) so as to record all"
	echo "logs in order to resolve problems that you may (rather 'will', practically)"
	echo "encounter."
	echo " The solutions depend on the individual cases."
	echo " If the problem will be resolved by reconfiguration of the port option, execute"
	echo "'make config' at the corresponding port directory, and then restart this"
	echo "utility."
	echo " If the problem will be resolved by manual fetch of tarballs, do it and then"
	echo "restart this utility."
	echo " If the problem will be resolved by deleting a concerned package, do it by"
	echo "'pkg_delete -f {package}' (conventional package), 'pkg delete -f {package}'"
	echo "(new generation package, pkgng) or execute 'make deinstall' at the corresponding"
	echo "port directory, then execute '${APPNAME} ok add \$glob' where '\$glob' is the"
	echo "ports glob of the concerned port, and then restart this utility."
	echo " If the problem will be resolved by manual reinstallation using pkg_add(1)"
	echo "(conventional package), pkg add (pkg-add(8), pkgng) or so on, do it and glob of"
	echo "execute '${APPNAME} ok add \$glob' where '\$glob' is the ports the concerned"
	echo "port, and then restart this utility by 'redo' command."
	echo
	echo " The current package system is automatically detected; the new generation"
	echo "package (pkgng) is used if 'WITH_PKGNG=yes' is set and 'WITHOUT_PKGNG=yes' isf"
	echo "not set /etc/make.conf, and otherwise the conventional package is used."
	echo
	echo " If you are familiar to the mechanism of Ports Collections system, in order to"
	echo "minimize package conflictions, it may be a good idea to delete packages which "
	echo "you don't think necessary before starting to use this utility."
	echo "Don't be afraid to delete necessary dependencies because all required ports are"
	echo "automatically installed."
	echo
	echo " If you run into confusion, it may be a good idea to clean up the temporal"
	echo "database by executing '${APPNAME} clean' and start again from the first."
	exit
fi

if [ $show_version = yes ]
then
	echo "${APPNAME} version ${MYVERSION}"
	exit
fi

command=$1
[ -z "$command" ] || shift

# ====================================================
# ================== FUNCTIONS =======================
# ====================================================

PORTSDIR=${PORTSDIR:-/usr/ports}

PORTS_MOVED_DB=${PORTSDIR}/MOVED
PORTS_INDEX_DB=${PORTSDIR}/INDEX-`uname -r | cut -d . -f 1`

WITH_PKGNG=`make -C "${PORTSDIR}" -V WITH_PKGNG | tr '[:upper:]' '[:lower:]'`

if [ "x$WITH_PKGNG" = xyes ]
then
	which -s pkg || { echo "ERROR: WITH_PKGNG is set, but pkgng is not available" >&2; exit 1; }
	command_pkg_info='pkg info'
	command_pkg_create='pkg create'
	command_pkg_delete='pkg delete'
	command_pkg_add='pkg add'
	pkg_info_qoa ()
	{
		pkg info -qoa 2> /dev/null
	}
	pkg_info_qox ()
	{
		pkg info -qox "$@" 2> /dev/null
	}
	pkg_info_qoX ()
	{
		pkg info -qoX "$@" 2> /dev/null
	}
	pkg_info_qO ()
	{
		pkg info -qO "$@" 2> /dev/null
	}
	pkg_info_qo ()
	{
		pkg info -qo "$@" 2> /dev/null
	}
	pkg_info_qr ()
	{
		pkg info -qd "$@" 2> /dev/null
	}
	pkg_info_e ()
	{
		pkg info -e "$@" 2> /dev/null
	}
	pkg_info_qR ()
	{
		pkg info -qr "$@" 2> /dev/null
	}
	pkg_info_Ex ()
	{
		pkg info -Ex "$@" 2> /dev/null
	}
	pkg_create_b ()
	{
		pkg create "$@"
	}
	pkg_delete_f ()
	{
		pkg delete -fqy "$@"
	}
	pkg_add_f ()
	{
		env ASSUME_ALWAYS_YES=YES pkg add "$@"
	}
	pkg_add_fF ()
	{
		env ASSUME_ALWAYS_YES=YES pkg add "$@"
	}
else
	unset WITH_PKGNG
	command_pkg_info='pkg_info'
	command_pkg_create='pkg_create'
	command_pkg_delete='pkg_delete'
	command_pkg_add='pkg_add'
	pkg_info_qoa ()
	{
		pkg_info -qoa 2> /dev/null
	}
	pkg_info_qox ()
	{
		pkg_info -qox "$@" 2> /dev/null
	}
	pkg_info_qoX ()
	{
		pkg_info -qoX "$@" 2> /dev/null
	}
	pkg_info_qO ()
	{
		pkg_info -qO "$@" 2> /dev/null
	}
	pkg_info_qo ()
	{
		pkg_info -qo "$@" 2> /dev/null
	}
	pkg_info_qr ()
	{
		pkg_info -qr "$@" | grep '^@pkgdep ' | sed 's/^@pkgdep[[:space:]]*//' 2> /dev/null
	}
	pkg_info_e ()
	{
		pkg_info -e "$@" 2> /dev/null
	}
	pkg_info_qR ()
	{
		pkg_info -qR "$@" | grep -v '^$' 2> /dev/null
	}
	pkg_info_Ex ()
	{
		pkg_info -Ex "$@" 2> /dev/null
	}
	pkg_create_b ()
	{
		pkg_create -b "$@"
	}
	pkg_delete_f ()
	{
		pkg_delete -f "$@"
	}
	pkg_add_f ()
	{
		pkg_add -f "$@"
	}
	pkg_add_fF ()
	{
		pkg_add -fF "$@"
	}
fi

str_escape_regexp_filter ()
{
	sed 's/\\/\\\\/g;s/|/\\|/g;s/\./\\./g;s|/|\\/|g;s/\[/\\[/g;s/\]/\\]/g;s/[(]/\\(/g;s/[)]/\\)/g;s/\+/\\+/g;s/\?/\\?/g;s/\*/\\*/g'
}

convert_glob_to_regexp_pattern ()
{
	sed 's/\+/\\+/g;s/\./\\./g;s|/|\\/|g;s/\*/.*/g;s/\?/g./;s/\[\!/[^/g;s/^/^/;s/$/$/'
}

convert_portsglob_to_regexp_pattern ()
{
	local glob_pattern regexp_pattern
	glob_pattern=$1
	if expr "$glob_pattern" : '^:' > /dev/null 2>&1
	then
		regexp_pattern=`echo "$glob_pattern" | sed 's/^://'`
	else
		regexp_pattern=`echo "$glob_pattern" | convert_glob_to_regexp_pattern`
	fi
	echo "$regexp_pattern"
}

if which -s ports_glob
then
	:
else
	ports_glob ()
	{
		local glob index
		[ -f "${DBDIR}/ports_glob:pkg.lst" ] || cut -d \| -f 1 "${PORTS_INDEX_DB}" > ${DBDIR}/ports_glob:pkg.lst
		[ -f "${DBDIR}/ports_glob:origin.lst" ] || cut -d \| -f 2 "${PORTS_INDEX_DB}" | sed -E "s/^`str_escape_regexp "${PORTSDIR}"`\///" > ${DBDIR}/ports_glob:origin.lst
		while [ $# -gt 0 ]
		do
			glob=`convert_portsglob_to_regexp_pattern "$1"`
			if expr "$glob" : '[^/][^/]*\/[^/][^/]*$' 2> /dev/null > /dev/null
			then
				grep -E "$glob" "${DBDIR}/ports_glob:origin.lst" || :
				pkg_info_qoa | grep -E "$glob" || :
			else
				grep -n -E "$glob" "${DBDIR}/ports_glob:pkg.lst" | cut -d : -f 1 | while read index
				do
					sed -n ${index}p "${DBDIR}/ports_glob:origin.lst"
				done || :
				pkg_info_qox "$glob" || :
			fi
			shift
		done | sort -u
	}
fi

str_escape_regexp ()
{
	echo "$*" | str_escape_regexp_filter
}

rm_a_line ()
{
	local item dstpath pattern
	item=$1
	dstpath=$2
	pattern=`str_escape_regexp "$item"`
	grep -v -E "^$pattern$" "$dstpath" 2> /dev/null > ${TMPDIR}/rm_a_line || :
	mv "${TMPDIR}/rm_a_line" "$dstpath"
}

add_a_line_if_new ()
{
	local item dstpath pattern
	item=$1
	dstpath=$2
	pattern=`str_escape_regexp "$item"`
	grep -m 1 -E "^$pattern$" "$dstpath" 2> /dev/null > /dev/null || echo "$item" >> $dstpath
}

record_success ()
{
	local origin clean recurse
	origin=$1
	str_escape_regexp_filter < ${DBDIR}/failed.list | sed "s|^|^|; s|$|$|" > ${TMPDIR}/record_success.grep_failed.list.tmp
	if [ `grep -m 1 -E -f "${TMPDIR}/record_success.grep_failed.list.tmp" "${DBDIR}/requires/$origin/requires" | wc -l` -eq 0 ]
	then
		add_a_line_if_new "$origin" "${DBDIR}/success.list"
		rm_a_line "$origin" "${DBDIR}/success_but_dependencies_failed.list"
		[ ! -e "${DBDIR}/requires/$origin/necessary_update" ] || mv "${DBDIR}/requires/$origin/necessary_update" "${DBDIR}/requires/$origin/necessary_update_completed"
	else
		rm_a_line "$origin" "${DBDIR}/success.list"
		add_a_line_if_new "$origin" "${DBDIR}/success_but_dependencies_failed.list"
	fi
	rm_a_line "$origin" "${DBDIR}/failed.list"
	rm -f "${DBDIR}/requires/$origin/note_failtre"
}

record_failure ()
{
	local origin clean
	origin=$1
	clean=$2
	add_a_line_if_new "$origin" "${DBDIR}/failed.list"
	rm_a_line "$origin" "${DBDIR}/success.list"
	rm_a_line "$origin" "${DBDIR}/success_but_dependencies_failed.list"
	if [ -z "$clean" -o "@$clean" = @clean ]
	then
		echo "*** Trying to clean the failed build... (Ignore failures)"
		env ${MAKE_ENVS} make clean ${MAKE_ARGS} || :
	fi
	echo "*** Skipping this port and proceeding to the next one forcibly..."
	echo
}

add_a_line_to_files_if_new ()
{
	local item
	item=$1
	while read filepath
	do
		add_a_line_if_new "$item" "$filepath"
	done
}

add_lines_if_new ()
{
	local filepath origin advance
	filepath=$1
	advance=$2
	while read origin
	do
		grep -m 1 -E "^`str_escape_regexp $origin`$" "$filepath" 2> /dev/null > /dev/null || echo $origin
	done > ${TMPDIR}/add_lines_if_new
	if [ "@$advance" = @advance ]
	then
		mv "$filepath" ${TMPDIR}/add_lines_if_new.bak
		cat "${TMPDIR}/add_lines_if_new" "${TMPDIR}/add_lines_if_new.bak" > $filepath
	else
		cat "${TMPDIR}/add_lines_if_new" >> $filepath
	fi
}

register_globs ()
{
	local globlist listpath mode dirpath origin
	globlist1=$1
	globlist2=$2
	listpath=$3
	mode=$4
	dirpath=`dirname "$listpath"`
	echo "`echo "$globlist1" | sed 's/,/ /g'`" "$globlist2" | sed -E 's/ +/\
/g' | grep -v '^$' | while read glob
	do
		if expr "@$glob" : '^@[^/][^/]*\/[^/][^/]*$' > /dev/null 2> /dev/null
		then
			[ ! -d "${PORTSDIR}/$glob" ] || { echo "$glob"; continue; }
		fi
		ports_glob "$glob" > ${TMPDIR}/register_globs:ports_glob
		origin=`ports_glob "$glob"`
		[ `cat "${TMPDIR}"/register_globs:ports_glob | wc -l` -ge 1 ] || \
		{
			echo "WARNING: No matching ports/package glob [$glob]" >&2
			continue
		}
		cat "${TMPDIR}"/register_globs:ports_glob
	done | while read origin
	do
		[ -d "$dirpath" ] || mkdir -p "$dirpath"
		if [ "@$mode" = @remove ]
		then
			rm_a_line "$origin" "$listpath"
		elif grep -m 1 -E "^`str_escape_regexp $origin`$" "$listpath" > /dev/null 2> /dev/null
		then
			:
		else
			echo $origin >> "$listpath"
		fi
	done
}

expand_glob_pattern_to_origins ()
{
	local glob_pattern include_nonexistent regexp_pattern
	glob_pattern=$1
	include_nonexistent=$2
	{
		ports_glob "$glob_pattern" 2> /dev/null || :
		if expr "$glob_pattern" : '^[a-z][a-z]*\/[a-zA-Z0-9_+-][a-zA-Z0-9_+-]*$' > /dev/null 2>&1
		then
			if [ "x$include_nonexistent" = xyes ]
			then
				echo "$glob_pattern"
			else
				pkg_info_qO "$glob_pattern" | xargs pkg_info_qo
			fi
		elif expr "$glob_pattern" : '^[a-zA-Z0-9.,_+-][a-zA-Z0-9.,_+-]*$' > /dev/null 2>&1
		then
			pkg_info_qo "$glob_pattern" 2> /dev/null || :
		else
			regexp_pattern=`convert_portsglob_to_regexp_pattern "$glob_pattern"`
			if expr "$glob_pattern" : '.*\/' > /dev/null 2>&1
			then
				pkg_info_qoa | grep -E "$regexp_pattern" 2> /dev/null || :
			else
				pkg_info_qoX "$regexp_pattern" 2> /dev/null || :
			fi
		fi
	} | grep -v -e '^$' | sort -u
}

build_conflist_target_list ()
{
	local section
	section=$1
	if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_${section}" ]
	then
		echo "-- ${section}_*"
		set | grep -e "^_CONF_${section}_" | cut -d = -f 1 | while read var
		do
			eval glob_pattern=\${$var}
			expand_glob_pattern_to_origins "$glob_pattern"
		done > ${DBDIR}/${section}_PORTS.conflist
		touch "${DBDIR}/COMPLETE_REFLECTCONF_${section}"
	fi
}

build_conflist_target_val_pair ()
{
	local section tag_target tag_val
	section=$1
	tag_target=$2
	tag_val=$3
	if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_${section}" ]
	then
		echo "-- ${section}_*"
		set | grep -e "^_CONF_${section}_${tag_target}_" | cut -d = -f 1 | while read var
		do
			eval glob_pattern=\${$var}
			eval val=\$\{`echo $var | sed "s/^_CONF_${section}_${tag_target}_/_CONF_${section}_${tag_val}_/"`\}
			expand_glob_pattern_to_origins "$glob_pattern" | while read origin
			do
				path=${DBDIR}/requires_conflist/$origin
				[ -d "$path" ] || mkdir -p "$path"
				echo "$val" > $path/${section}.conflist
			done
		done
		touch "${DBDIR}/COMPLETE_REFLECTCONF_${section}"
	fi
}

add_to_obsolete_if_not_yet ()
{
	local origin pkgtag
	origin=$1
	add_a_line_if_new "$origin" "${DBDIR}/moved_or_lost.list"
	if [ ! -e "${DBDIR}/obsolete/$origin/pkgtag" ]
	then
		[ -d "${DBDIR}/obsolete/$origin" ] || mkdir -p "${DBDIR}/obsolete/$origin"
		pkgtag=`pkg_info_qO "$origin"`
		[ -n "$pkgtag" ] || pkgtag='[not installed]'
		echo "$pkgtag" > ${DBDIR}/obsolete/$origin/pkgtag
	fi
}

convert_origin_if_moved ()
{
	local origin_src recursedb_in recursedb iline_db date_moved why_moved
	# input/output origin
	origin_src=$1
	recursedb_in=$2
	recursedb=${recursedb_in:-${PORTS_MOVED_DB}}
	[ ! -d "${PORTSDIR}/$origin" ] || return 0
	add_to_obsolete_if_not_yet "$origin"
	grep -n -m 1 -E "^`str_escape_regexp $origin`\|" "$recursedb" 2> /dev/null > ${TMPDIR}/moved.info || :
	if [ `cat "${TMPDIR}/moved.info" | wc -l` -eq 0 ]
	then
		if [ -n "$recursedb_in" ]
		then
			echo "${DEPTH_INDEX}  ===> Disappeared port (MOVED broken?)"
		else
			echo "${DEPTH_INDEX}  ===> Nonexistent port (your original?)"
		fi
		[ -z "$origin_src" ] || add_to_obsolete_if_not_yet "$origin_src"
		return 1
	else
		iline_db=`cut -d : -f 1 "${TMPDIR}/moved.info"`
		sed 1,${iline_db}d "${PORTS_MOVED_DB}" > ${TMPDIR}/MOVED.DB
		origin=`sed -E 's/^[0-9]+://' "${TMPDIR}/moved.info" | cut -d '|' -f 2 || :`
		date_moved=`cut -d '|' -f 3 "${TMPDIR}/moved.info" || :`
		why_moved=`cut -d '|' -f 4 "${TMPDIR}/moved.info" || :`
		if [ -n "$origin" ]
		then
			echo "${DEPTH_INDEX}  ===> Moved to $origin at $date_moved because \"$why_moved\""
			convert_origin_if_moved "$origin_src" "${TMPDIR}/MOVED.DB" || return 1
		else
			echo "${DEPTH_INDEX}  ===> Deleted at $date_moved because \"$why_moved\""
			[ -n "$origin_src" ] || return 1
			origin=$origin_src
			echo "${DEPTH_INDEX}  ===> Going back to the original port $origin_src"
			convert_origin_if_moved || return 1
		fi
	fi
}

inspect_dependencies ()
{
	local origin origin_orig pkg origin_id origin_src port_exists origin_dependency DEPTH_INDEX_orig nlines iline is_suppressed
	origin=$1
	origin_orig=$origin
	DEPTH_INDEX_orig=${DEPTH_INDEX}
	DEPTH_INDEX="${DEPTH_INDEX}--"
	echo "${DEPTH_INDEX} $origin"
	origin_id=`echo $origin | tr / :`
	pkg=`pkg_info_qO "$origin"`
	if [ -n "$pkg" ]
	then
		target_dir=${DBDIR}/initial/$origin
		[ -d "$target_dir" ] || mkdir -p "$target_dir"
		echo $pkg > $target_dir/installed_version
		pkg_info_qr "$pkg" | while read requirement
		do
			pkg_info_e "$requirement" || continue
			pkg_info_qo "$requirement" >> $target_dir/requires
		done
		pkg_info_qR "$pkg" | while read dependent
		do
			pkg_info_e "$dependent" || continue
			pkg_info_qo "$dependent" >> $target_dir/dependents
		done
	fi
	if [ $supress_self_upadte = yes -a `expr "$pkg" : "^${APPNAME}-[0-9].*"` -gt 0 ]
	then
		is_supressed=yes
	else
		is_supressed=no
	fi
	origin_src=
	if [ `echo $origin | grep -m 1 -E -f "${DBDIR}/REPLACE.grep_from_pattern.conflist" | wc -l` -eq 1 ]
	then
		origin_src=$origin
		origin=`echo $origin_src | sed -E -f "${DBDIR}/REPLACE.replace_pattern.conflist"`
		if [ $is_supressed = yes ]
		then
			if [ -n "$origin" ]
			then
				echo "${DEPTH_INDEX}  ===> Replaced with $origin by user configuration (ignored)"
			else
				echo "${DEPTH_INDEX}  ===> Deleted by user configuration (ignored)"
			fi
		else
			add_to_obsolete_if_not_yet "$origin_src"
			if [ -n "$origin" ]
			then
				add_a_line_if_new "$origin" "${DBDIR}/replaced_target.inspected.list"
				echo "${DEPTH_INDEX}  ===> Replaced with $origin by user configuration"
			else
				echo "${DEPTH_INDEX}  ===> Deleted by user configuration"
			fi
		fi
	fi
	if [ -n "$origin" ]
	then
		if convert_origin_if_moved "$origin_src" ''
		then
			port_exists=yes
		else
			port_exists=no
		fi
		if [ $port_exists = yes ]
		then
			rm_a_line "$origin" "${DBDIR}/moved_or_lost.list"
			cd "${PORTSDIR}/$origin"
			target_dir=${DBDIR}/requires/$origin
			[ -d "$target_dir/status" ] || mkdir -p "$target_dir/status"
			[ $is_supressed = no ] || touch "$target_dir/SUPPRESSED"
			if [ -d "${DBDIR}/requires_conflist/$origin" ]
			then
				cp -R "${DBDIR}/requires_conflist/$origin/"* "$target_dir/" > /dev/null 2> /dev/null || :
			fi
			MAKE_ARGS="FORCE_PKG_REGISTER=yes DISABLE_VULNERABILITIES=yes `cat "$target_dir/MARG.conflist" 2> /dev/null || :`"
			MAKE_ENVS=`cat "$target_dir/MENV.conflist" 2> /dev/null || :`
			env ${MAKE_ENVS} make config-conditional ${MAKE_ARGS}
			pkg=`pkg_info_qO "$origin"`
			[ -z "$pkg" ] || echo $pkg > $target_dir/installed_version
			pkg_new=`(cd "${PORTSDIR}/$origin" && env ${MAKE_ENVS} make package-name ${MAKE_ARGS})`
			pkgtag=$pkg
			[ -n "$pkgtag" ] || pkgtag=$pkg_new
			if [ -z "$pkgtag" ]
			then
				pkgtag='?'
			
			elif [ "z$pkg" != "z$pkg_new" ]
			then
				echo $pkg_new > $target_dir/new_version
				if [ -n "$pkg" ]
				then
					pkgtag="$pkg => $pkg_new"
				else
					pkgtag="[new] $pkg_new"
				fi
			fi
			echo $pkgtag > $target_dir/pkgtag
			env ${MAKE_ENVS} make all-depends-list ${MAKE_ARGS} | sed "s|^${PORTSDIR}/||" > "$target_dir/requires" || :
			grep -E -f "${DBDIR}/REPLACE.grep_from_pattern.conflist" "$target_dir/requires" | grep -v -E "^`str_escape_regexp $origin`$" > ${TMPDIR}/replaced_target.tmp || :
			mv "$target_dir/requires" "$target_dir/requires.orig"
			sed -E -f "${DBDIR}/REPLACE.replace_pattern.conflist" "$target_dir/requires.orig" | grep -v '^$' > $target_dir/requires || :
			add_lines_if_new "${DBDIR}/replaced_target.list" < ${TMPDIR}/replaced_target.tmp
			grep -v -E -f "${DBDIR}/installed_ports.grep_pattern" "$target_dir/requires" > ${TMPDIR}/missing.$origin_id || :
			nlines=`cat "${TMPDIR}/missing.$origin_id" | wc -l`
			iline=1
			while [ $iline -le $nlines ]
			do
				origin_dependency=`sed -n ${iline}p "${TMPDIR}/missing.$origin_id"`
				iline=$(($iline+1))
				if grep -m 1 -E "^`str_escape_regexp $origin_dependency`$" "${DBDIR}/target.inspected.list" > /dev/null 2> /dev/null
				then
					:
				else
					inspect_dependencies "$origin_dependency"
				fi
			done
			rm "${TMPDIR}/missing.$origin_id"
			env ${MAKE_ENVS} make fetch-urlall-list ${MAKE_ARGS} | sed -E 's|.*/([^/]+)$|\1|' | sort | uniq >> ${DBDIR}/distfiles.list
		fi
	fi
	[ "$origin_orig" = "$origin" ] || echo "s|^`str_escape_regexp $origin_orig`$|$origin|" >> ${DBDIR}/REPLACE.complete_replace_pattern.tmp
	add_a_line_if_new "$origin" "${DBDIR}/target.inspected.list"
	rm_a_line "$origin" "${DBDIR}/target_ports.remain"
	if [ -n "$origin_src" ]
	then
		add_a_line_if_new "$origin_src" "${DBDIR}/target.inspected.list"
		rm_a_line "$origin_src" "${DBDIR}/target_ports.remain"
	fi
	echo "${DEPTH_INDEX}  ===> ok"

	DEPTH_INDEX=${DEPTH_INDEX_orig}
}

cmt_fail_reinst ()
{
	local origin
	origin=$1
	echo "*** Giving up for this port $origin and proceeding to the next one forcibly..."
	echo
}

timestamp ()
{
	env LANG= date
}

warn_update_ports ()
{
	[ ${_STATUS_DB_OBSOLETE} = yes ] || return 0
	echo "WARNING: The Ports tree was updated after construction of the temporal database for ${APPNAME}." >&2
	echo "      You should consider executing " >&2
	echo "               ${APPNAME} clean" >&2
	echo "     to reset the temporal database unless you have special purposes." >&2
}

linear_list ()
{
	echo "$*" | sed -E 's/^ +//; s/ +$//; s/ +/, /; s/, ([^ ]+)$/ and \1/'
}

chk_privilege ()
{
	[ `id -u` -eq 0 ] || { echo "ERROR: Only the superuser can execute this command." >&2; exit 1; }
}

combine_lists ()
{
	local src_conf src_opt dst
	src_conf=$1
	src_opt=$2
	dst=$3
	cat "${DBDIR}/$src_conf" "${DBDIR}/$src_opt" 2> /dev/null | sort | uniq > ${DBDIR}/$dst || :
}

show_list_failure ()
{
	[ -e "${DBDIR}"/failed.list ] || return 0
	while read origin
	do
		note=`cat "${DBDIR}/requires/$origin/note_failtre"`
		if grep -m 1 -E "^`str_escape_regexp $origin`$" "${DBDIR}/manually_done.list" > /dev/null 2>&1
		then
			resolved=', resolved'
		else
			resolved=
		fi
		if [ -e "${DBDIR}/requires/$origin/pkgtag" ]
		then
			pkgtag=' ('`cat "${DBDIR}/requires/$origin/pkgtag"`')'
		else
			pkgtag=
		fi
		echo "$origin$pkgtag (error while [$note]$resolved)"
	done < ${DBDIR}/failed.list
}

chk_if_target ()
{
	local prefix _is_all _is_target _is_required _is_former_required _is_dependent _is_former_dependent _is_relevant
	prefix=$1
	origin=$2
	if [ -e "${DBDIR}/all/$origin/chk_if_target.param" ]
	then
		. "${DBDIR}/all/$origin/chk_if_target.param"
	else
		_is_all=y
		_is_target=
		_is_required=
		_is_former_required=
		_is_dependent=
		_is_former_dependent=
		_is_relevant=y
		if [ `cat "${DBDIR}/target_required_ports.specified" 2> /dev/null | wc -l` -gt 0 ]
		then
			_is_all=
			if grep -m 1 -E "^`str_escape_regexp $origin`$" "${DBDIR}/target_required_ports.specified" > /dev/null 2> /dev/null
			then
				_is_target=y
			elif [ -e "${DBDIR}/requires/$origin/dependents.pattern" ] && grep -m 1 -E -f "${DBDIR}/requires/$origin/dependents.pattern" "${DBDIR}/target_required_ports.specified" > /dev/null 2> /dev/null
			then
				_is_required=y
			elif [ -e "${DBDIR}/initial/$origin/dependents.pattern" ] && grep -m 1 -E -f "${DBDIR}/initial/$origin/dependents.pattern" "${DBDIR}/target_required_ports.specified" > /dev/null 2> /dev/null
			then
				_is_former_required=y
			fi
		fi
		if [ `cat "${DBDIR}/target_dependent_ports.specified" 2> /dev/null | wc -l` -gt 0 ]
		then
			_is_all=
			if [ -n "${_is_target}" ] || grep -m 1 -E "^`str_escape_regexp $origin`$" "${DBDIR}/target_dependent_ports.specified" > /dev/null 2> /dev/null
			then
				_is_target=y
			elif [ -e "${DBDIR}/requires/$origin/requires.pattern" ] && grep -m 1 -E -f "${DBDIR}/requires/$origin/requires.pattern" "${DBDIR}/target_dependent_ports.specified" > /dev/null 2> /dev/null
			then
				_is_dependent=y
			elif [ -e "${DBDIR}/initial/$origin/requires.pattern" ] && grep -m 1 -E -f "${DBDIR}/initial/$origin/requires.pattern" "${DBDIR}/target_dependent_ports.specified" > /dev/null 2> /dev/null
			then
				_is_former_dependent=y
			fi
		fi
		[ -n "${_is_all}${_is_target}${_is_required}${_is_former_required}${_is_dependent}${_is_former_dependent}" ] || _is_relevant=
		echo _is_all=${_is_all} > ${TMPDIR}/chk_if_target:results
		echo _is_target=${_is_target} >> ${TMPDIR}/chk_if_target:results
		echo _is_required=${_is_required} >> ${TMPDIR}/chk_if_target:results
		echo _is_former_required=${_is_former_required} >> ${TMPDIR}/chk_if_target:results
		echo _is_dependent=${_is_dependent} >> ${TMPDIR}/chk_if_target:results
		echo _is_former_dependent=${_is_former_dependent} >> ${TMPDIR}/chk_if_target:results
		echo _is_relevant=${_is_relevant} >> ${TMPDIR}/chk_if_target:results
		[ -d "${DBDIR}/all/$origin" ] || mkdir -p "${DBDIR}/all/$origin"
		mv "${TMPDIR}"/chk_if_target:results "${DBDIR}/all/$origin/chk_if_target.param"
	fi
	eval ${prefix}_is_all=\$\{_is_all\}
	eval ${prefix}_is_target=\$\{_is_target\}
	eval ${prefix}_is_required=\$\{_is_required\}
	eval ${prefix}_is_former_required=\$\{_is_former_required\}
	eval ${prefix}_is_dependent=\$\{_is_dependent\}
	eval ${prefix}_is_former_dependent=\$\{_is_former_dependent\}
	eval ${prefix}_is_relevant=\$\{_is_relevant\}
}

register_globs_only_installed ()
{
	local src1 src2
	src1=$1
	src2=$2
	rm -f "${TMPDIR}/register_globs_only_installed:origins"
	register_globs "$src1" "$src2" "${TMPDIR}/register_globs_only_installed:origins"
	[ -e "${TMPDIR}/register_globs_only_installed:origins" ] || return 0
	while read origin
	do
		[ -z `pkg_info_qO "$origin"` ] || echo $origin
	done < ${TMPDIR}/register_globs_only_installed:origins
}


# ==================================================
# ==================== MAIN ========================
# ==================================================

# Title
credit
echo
echo " Don't hesitate to terminate by CTRL+C anytime you feel the system is heavy to"
echo "use because you can restart the operation from the terminated point quickly."
echo
echo "The current time is `timestamp`"
echo

# Check of conflicting option
[ -z "$target_dependent_ports" -o ! -e "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS" ] || echo "WARNING: -t option is specified but ignored because we are restarting the previous run." >&2
[ -z "$target_required_ports" -o ! -e "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS" ] || echo "WARNING: -T option is specified but ignored because we are restarting the previous run." >&2
[ -z "$target_dependent_ports_form2" -o ! -e "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS" ] || echo "WARNING: -r option is specified but ignored because we are restarting the previous run." >&2
[ -z "$target_required_ports_form2" -o ! -e "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS" ] || echo "WARNING: -R option is specified but ignored because we are restarting the previous run." >&2
[ "$load_pkgtoolsconf" = undef -o ! -e "${DBDIR}/COMPLETE_IMPORT_PKGTOOLS_CONF" ] || echo "WARNING: -p, -P or -Q option is specified but ignored by following the previous settings." >&2

# Check whether the temporal database is newer than the ports tree
if [ "${PORTS_INDEX_DB}" -nt "${DBDIR}"/MYVERSION ]
then
	if [ $supress_obsolete_db_clean = no ]
	then
		_STATUS_DB_OBSOLETE=no
		if [ "z${command}" != zclean ]
		then
			echo "INFO: The temporal database is cleaned up because it is older than the ports tree."
			echo
			rm -rf "${DBDIR}"
		fi
	else
		_STATUS_DB_OBSOLETE=yes
	fi
else
	_STATUS_DB_OBSOLETE=no
fi

# Update portsreinstall itself if it is newer in the ports tree
if [ $supress_self_upadte = no -a `id -u` -eq 0 -a \( ! -e "${DBDIR}" -o ${_STATUS_DB_OBSOLETE} = yes \) ]
then
	pkg_info_Ex "${APPNAME}-[0-9].*" > ${TMPDIR}/self_version || :
	num_self_versions=`cat "${TMPDIR}"/self_version | wc -l`
	if [ $num_self_versions -gt 1 ]
	then
		echo "ERROR: Multiple versions of ${APPNAME} are installed. This is unexpected." >&2
		exit 1
	elif [ $num_self_versions -eq 1 ]
	then
		self_origin=`pkg_info_qo "\`cat \"${TMPDIR}\"/self_version\`"`
		[ -d "${PORTSDIR}/$self_origin" ] || { echo "ERROR: ${PORTSDIR}/$self_origin does not exist" >&2; exit 1; }
		self_pkg_current=`cat "${TMPDIR}"/self_version`
		self_pkg_new=`( cd "${PORTSDIR}/$self_origin" && make package-name )`
		if [ -n "$self_pkg_new" ]
		then
			if [ "$self_pkg_new" != `cat "${TMPDIR}"/self_version` ]
			then
				echo "INFO: The ports tree has a new version of ${APPNAME}. It will be updated first."
				echo "Updating $self_origin ($self_pkg_current => $self_pkg_new)..."
				echo "Backing up the installed package..."
				[ -d "${PORTSDIR}"/packages/All ] || mkdir -p "${PORTSDIR}"/packages/All
				( cd "${PORTSDIR}"/packages/All/ && pkg_create_b "$self_pkg_current" )
				echo "Reinstalling ${APPNAME}..."
				pkg_delete_f "$self_pkg_current"
				if ( cd "${PORTSDIR}/$self_origin" && make reinstall )
				then
					( cd "${PORTSDIR}/$self_origin" && make clean )
					if [ $supress_obsolete_db_clean = yes -a -d "${DBDIR}" ]
					then
						echo "INFO: Cleaning the temporal database..."
						rm -rf "${DBDIR}"
						echo
					fi
					echo "INFO: Restarting with the new version..."
					echo
					. "${TMPDIR}"/restart_command.sh
					echo "ERROR: Failed to launch the new version" >&2
					exit 1
				else
					echo "WARNING: Reinstallation failed. Restoring the old package..." >&2
					( cd "${PORTSDIR}/$self_origin" && make deinstall ) || :
					( cd "${PORTSDIR}/$self_origin" && make clean ) || :
					pkg_add_f "${PORTSDIR}"/packages/All/"$self_pkg_current.tbz"
					echo "INFO: Continuing with the old version..."
				fi
			fi
		else
			echo "WARNING: No port for ${APPNAME} exists in the current ports tree" >&2
		fi
	else
		echo "INFO: This version of ${APPNAME} has been installed not by ports/packages mechanism."
		echo "Thus any updates on ${APPNAME} will be ignored."
	fi
fi

# Creation of temporal database directory
if [ -d "${DBDIR}" ]
then
	DBVERSION=`cat "${DBDIR}"/MYVERSION 2> /dev/null || :`
	# Reserved for compatibility check
else
	mkdir -p "${DBDIR}"
	echo ${MYVERSION} > ${DBDIR}/MYVERSION
fi

# Taboo list given by options
register_globs "$taboo_ports" "$taboo_ports_form2" "${DBDIR}/taboo.list"

# ------- Commands -------

# Special modes
case ${command:-do} in
clean)
	chk_privilege
	echo "Starting to clean up the temporal database..."
	rm -rf "${DBDIR}"
	echo "Done"
	exit
	;;
ok)
	chk_privilege
	warn_update_ports
	opr=$1
	shift
	case $opr in
	add)
		register_globs '' "$*" "${DBDIR}/manually_done.list"
		echo "`linear_list \"$*\"` is/are registered to the list of manually resolved ports"
		;;
	del)
		register_globs '' "$*" "${DBDIR}/manually_done.list" remove
		echo "`linear_list \"$*\"` is/are deregistered from the list of manually resolved ports"
		;;
	esac
	echo "Now the following ports have been manually resolved:"
	[ ! -r "${DBDIR}/manually_done.list" ] || cat  "${DBDIR}/manually_done.list"
	exit
	;;
taboo)
	chk_privilege
	warn_update_ports
	opr=$1
	shift
	case $opr in
	add)
		register_globs '' "$*" "${DBDIR}/taboo.list"
		echo "`linear_list \"$*\"` is/are registered to the list of ports to be ignored."
		;;
	del)
		register_globs '' "$*" "${DBDIR}/taboo.list" remove
		echo "`linear_list \"$*\"` is/are deregistered from the list of ports to be ignored."
		;;
	esac
	combine_lists TABOO_PORTS.conflist taboo.list taboo.all.list
	echo "Now the following ports are registered to be ignored:"
	cat "${DBDIR}/taboo.all.list"
	exit
	;;
save)
echo $*
	chk_privilege
	[ -d "${DBDIR}" ] || { echo "ERROR: Database has not been built up yet." >&2; exit 1; }
	savedir=$1
	[ -n "$savedir" ] || { echo "ERROR: Directory to save the temporal database archive is not specified." >&2; exit 1; }
	[ -d "$savedir" ] || { echo "ERROR: Directory [$savedir] is not found." >&2; exit 1; }
	srcdir=`dirname "${DBDIR}"`
	srcnode=`basename "${DBDIR}"`
	savefile=`realpath "$savedir"`/${APPNAME}_`date +%Y%m%d_%H%M%S`.tar.gz
	echo "Starting to save the temporal database as [$savefile]..."
	( cd "$srcdir" && tar czf "$savefile" "$srcnode" )
	echo "Done"
	exit
	;;
load)
	chk_privilege
	loadfile=$1
	[ -n "$loadfile" ] || { echo "ERROR: Database archive is not specified." >&2; exit 1; }
	[ -f "$loadfile" ] || { echo "ERROR: Database archive is not found." >&2; exit 1; }
	loadfile=`realpath "$loadfile"`
	echo "Starting to load the temporal database..."
	rm -rf "${DBDIR}"
	srcdir=`dirname "${DBDIR}"`
	srcnode=`basename "${DBDIR}"`
	[ -d "$srcdir" ] || mkdir -p "$srcdir"
	( cd "$srcdir" && tar xzf "$loadfile" )
	echo "Done"
	exit
	;;
show)
	[ -e "${DBDIR}/COMPLETE_PREPARATION" ] || { echo "ERROR: Database has not built yet." >&2; exit 1; }
	warn_update_ports
	_filter_skip_unchanged=
	_filter_only_target=
	_for_each_matching_port=
	pkgnamedb=requires
	case ${1:-todo} in
	todo)
		echo "The following ports are to be reinstalled or newly installed:"
		list=reinst_todo.list
		[ -e "${DBDIR}/reinst_todo.list" ] || list=reinst_order.list
		_filter_skip_unchanged=necessary_update
		_filter_only_target=y
		;;
	done)
		echo "The following ports have been successfully reinstalled or newly installed:"
		list=success.list
		_filter_skip_unchanged=necessary_update_completed
		_filter_only_target=y
		;;
	redo)
		echo "The following ports themselves have been successfully reinstalled or newly installed,"
		echo "but are to be reinstalled again because their dependencies were failed:"
		list=success_but_dependencies_failed.list
		_filter_skip_unchanged=necessary_update
		_filter_only_target=y
		;;
	resolved)
		echo "The following ports had problems which have been manually resolved:"
		list=manually_done.list
		;;
	failure)
		echo "The following ports experienced failures and kept to be old:"
		show_list_failure
		exit
		;;
	taboo)
		echo "The following ports are registered as taboo:"
		list=taboo.all.list
		;;
	deleted)
		echo "The following ports are to be or have been deleted:"
		list=moved_or_lost.actual.list
		pkgnamedb=obsolete
		_filter_only_target=y
		;;
	requirements)
		grandtitle="Dependencies based on the latest ports tree"
		title="The following ports are required by %s:"
		list=requires
		_for_each_matching_port=y
		;;
	dependents)
		grandtitle="Dependencies based on the latest ports tree"
		title="The following ports depend on %s:"
		list=dependents
		_for_each_matching_port=y
		;;
	*)
		echo "ERROR: Invalid show argument [$1]" >&2
		exit 1
		;;
	esac
	[ -n "${_for_each_matching_port}" -o -r "${DBDIR}/$list" ] || exit 0
	[ ! -e "${DBDIR}"/saved_options.sh ] || . "${DBDIR}"/saved_options.sh
	if [ -n "${_for_each_matching_port}" ]
	then
		shift
		[ $# -gt 0 ] || { echo "ERROR: the argument as port glob is missing" >&2; exit 1; }
		echo "[$grandtitle]"
		echo
		isfirst=y
		for origin_target in `ports_glob "$@"`
		do
			[ -e "${DBDIR}/requires/$origin_target/pkgtag" ] || continue
			[ "$isfirst" = y ] || echo
			isfirst=n
			pkg_target=`cat "${DBDIR}/$pkgnamedb/$origin_target/pkgtag"`
			printf "$title\n" "$origin_target ($pkg_target)"
			[ -e "${DBDIR}/requires/$origin_target/$list" ] || continue
			while read origin
			do
				if [ -e "${DBDIR}/$pkgnamedb/$origin/pkgtag" ]
				then
					echo $origin '('`cat "${DBDIR}/$pkgnamedb/$origin/pkgtag"`')'
				else
					echo $origin
				fi
			done < ${DBDIR}/requires/$origin_target/$list
		done
		[ "$isfirst" = n ] || { echo "ERROR: no matching port for the glob" >&2; exit 1; }
	elif [ -n "${_filter_skip_unchanged}" -a $skip_unchanged = yes ]
	then
		while read origin
		do
			[ -e "${DBDIR}/requires/$origin/${_filter_skip_unchanged}" ] || continue
			if [ -n "${_filter_only_target}" ]
			then
				chk_if_target currentorigin "$origin"
				[ -n "${currentorigin_is_relevant}" ] || continue
				[ ! -e "${DBDIR}/requires/$origin/SUPPRESSED" ] || continue
			fi
			if [ -e "${DBDIR}/$pkgnamedb/$origin/pkgtag" ]
			then
				echo $origin '('`cat "${DBDIR}/$pkgnamedb/$origin/pkgtag"`')'
			else
				echo $origin
			fi
		done < ${DBDIR}/$list
	else
		while read origin
		do
			if [ -n "${_filter_only_target}" ]
			then
				chk_if_target currentorigin "$origin"
				[ -n "${currentorigin_is_relevant}" ] || continue
				[ ! -e "${DBDIR}/requires/$origin/SUPPRESSED" ] || continue
			fi
			if [ -e "${DBDIR}/$pkgnamedb/$origin/pkgtag" ]
			then
				echo $origin '('`cat "${DBDIR}/$pkgnamedb/$origin/pkgtag"`')'
			else
				echo $origin
			fi
		done < ${DBDIR}/$list
	fi
	exit
	;;
redo)
	chk_privilege
	warn_update_ports
	touch "${DBDIR}/MODE_REDO"
	rm -f "${DBDIR}/COMPLETE_CLEANUP_REINST_STATUS"
	[ $renew_options = no ] || rm -f "${DBDIR}/COMPLETE_SAVE_OPTIONS"
	if [ -n "$target_required_ports$target_dependent_ports$target_required_ports_form2$target_dependent_ports_form2" ]
	then
		rm -f "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS"
		touch "${DBDIR}/REQUIRE_CHK_NEW_TARGET"
	fi
	echo "[REDO mode]"
	;;
prepare)
	chk_privilege
	warn_update_ports
	;;
do)
	chk_privilege
	;;
*)
	echo "ERROR: Invalid command [$command]" >&2
	exit 1
	;;
esac

# ------- Termination messages during construction of the temporal database -------

terminate_process_common ()
{
	local msg_where
	[ -z "${_MSG_CURRENT_STAGE}" ] || msg_where=" during ${_MSG_CURRENT_STAGE}"
	echo
	if [ $errno -eq 130 ]
	then
		echo "INFO: Terminated at `timestamp`$msg_where"
		echo
		echo " You can restart this process from the terminated point by"
	else
		echo "INFO: Aborted at `timestamp`$msg_where"
		echo
		echo " You may restart this process from the aborted point by"
	fi
	echo "executing without options or arguments as:"
	echo "  ${APPNAME}"
}

terminate_process ()
{
	terminate_process_common
	echo " Instead, if you only want to construct the temporal database so as to stop"
	echo "before the actual reinstallation, execute as:"
	echo "  ${APPNAME} prepare"
	terminate_process ()
	{
	}
}

# ------- Load from pkgtools.conf(5) -------

if [ ! -e "${DBDIR}/COMPLETE_SAVE_OPTIONS" ]
then
	[ ! -e "${DBDIR}"/saved_options.sh ] || echo "(Previous option settings for '-s', '-q' and '-d' are reset.)"
	set | grep -e '^target_dependent_ports=' \
		-e '^target_required_ports=' \
		-e '^target_dependent_ports_form2=' \
		-e '^target_required_ports_form2=' \
		-e '^taboo_ports=' \
		-e '^taboo_ports_form2=' \
		-e '^load_pkgtoolsconf=' \
		-e '^avoid_vulner=' \
		-e '^skip_unchanged=' \
		-e '^keep_distfiles=' \
		-e '^renew_options=' \
		-e '^supress_self_upadte=' \
		-e '^supress_obsolete_db_clean=' \
		> ${DBDIR}/saved_options.sh || :
	touch "${DBDIR}/COMPLETE_SAVE_OPTIONS"
else
	t_avoid_vulner=$avoid_vulner
	t_skip_unchanged=$skip_unchanged
	t_keep_distfiles=$keep_distfiles
	. "${DBDIR}"/saved_options.sh
	[ $t_avoid_vulner = no -o $t_avoid_vulner = $avoid_vulner ] || echo "WARNING: -s option is specified but ignored by transferring the settings from the previous run." >&2
	[ $t_skip_unchanged = no -o $t_skip_unchanged = $skip_unchanged ] || echo "WARNING: -q option is specified but ignored by transferring the settings from the previous run." >&2
	[ $t_keep_distfiles = no -o $t_keep_distfiles = $keep_distfiles ] || echo "WARNING: -d option is specified but ignored by transferring the settings from the previous run." >&2
fi

echo "INFO: List of option values:"
echo "-----------------------------------------"
cat "${DBDIR}"/saved_options.sh
echo "-----------------------------------------"
echo

if [ ! -e "${DBDIR}/COMPLETE_IMPORT_PKGTOOLS_CONF" ]
then
	PORTUPGRADE=`which portupgrade | head -n 1 || :`
	if [ $load_pkgtoolsconf = undef ]
	then
		if [ -n "${PORTUPGRADE}" -a -e /usr/local/etc/pkgtools.conf ]
		then
			load_pkgtoolsconf=default
		else
			load_pkgtoolsconf=no
		fi
	elif [ $load_pkgtoolsconf != undef -a `which portupgrade | wc -l` -eq 0 ]
	then
		echo "WARNING: pkgtools.conf is ignored because portupgrade is not installed" >&2
		load_pkgtoolsconf=no
	fi
	
	if [ $load_pkgtoolsconf != no ]
	then
		echo "-- Starting to parse pkgtools.conf at `timestamp` (by using installed portupgrade)"
		portupgrade_pkg=`pkg_info_qO ports-mgmt/portupgrade`
		[ -n "$portupgrade_pkg" ] || portupgrade_pkg=`pkg_info_qO ports-mgmt/portupgrade-devel`
		[ `expr "$portupgrade_pkg" : '^portupgrade-devel-'` -eq 0 ] || echo "WARNING: Combination with portupgrade-devel-* has not tested."
		istart=`grep -m 1 -n -e '^def init_global$' "${PORTUPGRADE}" | cut -d : -f 1` || :
		[ -n "$istart" ] || { echo "ERROR: The current installed version of portupgrade is unsupported." >&2; }
		sed 1,$(($istart-1))d "${PORTUPGRADE}" > ${TMPDIR}/portupgrade.0
		iend=`grep -m 1 -n -e '^end$' "${TMPDIR}"/portupgrade.0 | cut -d : -f 1`
		sed -n 1,${iend}p "${TMPDIR}"/portupgrade.0 > ${TMPDIR}/portupgrade.init_global
		ruby > ${DBDIR}/pkgtools.conf.converted << eof
MYNAME = 'portupgrade'
require 'pkgtools'
`cat "${TMPDIR}"/portupgrade.init_global`
init_global
init_pkgtools_global
load_config
alt_moved = config_value(:ALT_MOVED)
hold_pkgs = config_value(:HOLD_PKGS)
ignore_moved = config_value(:IGNORE_MOVED)
alt_pkgdep = config_value(:ALT_PKGDEP)
make_args = config_value(:MAKE_ARGS)
make_env = config_value(:MAKE_ENV)
beforebuild = config_value(:BEFOREBUILD)
beforedeinstall = config_value(:BEFOREDEINSTALL)
afterinstall = config_value(:AFTERINSTALL)

printf("ENV_PORTSDIR=%s\n", ENV['PORTSDIR'])

i = 0
alt_moved.each do |val|
        printf("ALT_MOVED_pkgtoolsconf_%d_='%s'\n", i, val)
        i = i + 1
end

i = 0
hold_pkgs.each do |val|
        printf("HOLD_pkgtoolsconf_%d_='%s'\n", i, val)
        i = i + 1
end
ignore_moved.each do |val|
        printf("HOLD_pkgtoolsconf_%d_='%s'\n", i, val)
        i = i + 1
end

i = 0
alt_pkgdep.each do |pat, alt|
        printf("REPLACE_FROM_pkgtoolsconf_%d_='%s'\n", i, pat)
        printf("REPLACE_TO_pkgtoolsconf_%d_='%s'\n", i, alt)
        i = i + 1
end

i = 0
make_args.each do |target, definition|
        printf("MARG_TARGET_pkgtoolsconf_%d_='%s'\n", i, target)
        printf("MARG_DEF_pkgtoolsconf_%d_='%s'\n", i, definition)
        i = i + 1
end

i = 0
make_env.each do |target, definition|
        printf("MENV_TARGET_pkgtoolsconf_%d_='%s'\n", i, target)
        printf("MENV_DEF_pkgtoolsconf_%d_='%s'\n", i, definition)
        i = i + 1
end

i = 0
beforebuild.each do |target, command|
        printf("BEFOREBUILD_TARGET_pkgtoolsconf_%d_='%s'\n", i, target)
        printf("BEFOREBUILD_COMMAND_pkgtoolsconf_%d_='%s'\n", i, command)
        i = i + 1
end

i = 0
beforedeinstall.each do |target, command|
        printf("BEFOREDEINSTALL_TARGET_pkgtoolsconf_%d_='%s'\n", i, target)
        printf("BEFOREDEINSTALL_COMMAND_pkgtoolsconf_%d_='%s'\n", i, command)
        i = i + 1
end

i = 0
afterinstall.each do |target, command|
        printf("AFTERINSTALL_TARGET_pkgtoolsconf_%d_='%s'\n", i, target)
        printf("AFTERINSTALL_COMMAND_pkgtoolsconf_%d_='%s'\n", i, command)
        i = i + 1
end
eof
		if [ $load_pkgtoolsconf = default ]
		then
			cat "${DBDIR}"/pkgtools.conf.converted "${CONFFILE}" > ${DBDIR}/setup.conf 
		elif [ $load_pkgtoolsconf = override ]
		then
			cat "${CONFFILE}" "${DBDIR}"/pkgtools.conf.converted > ${DBDIR}/setup.conf
		fi
		echo "===> ok"
		echo
	else
		ln -s "${CONFFILE}" "${DBDIR}"/setup.conf
	fi
	touch "${DBDIR}/COMPLETE_IMPORT_PKGTOOLS_CONF"
fi

# ------- Configurations -------
if [ -n "$taboo_ports$taboo_ports_form2" ]
then
	echo "INFO: (Re-)installation of the following ports are avoided as taboo:"
	echo "----------------------------------------"
	[ ! -e "${DBDIR}"/taboo.list ] || cat "${DBDIR}"/taboo.list
	echo "----------------------------------------"
	echo
fi

if [ ! -e "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS" ]
then
	rm -f "${DBDIR}/target_dependent_ports.specified" "${DBDIR}/target_required_ports.specified"
	register_globs_only_installed "$target_dependent_ports" "$target_dependent_ports_form2" > ${DBDIR}/target_dependent_ports.specified
	register_globs_only_installed "$target_required_ports" "$target_required_ports_form2" > ${DBDIR}/target_required_ports.specified
	touch "${DBDIR}/COMPLETE_PARSE_OPTION_TARGET_PORTS"
fi
if [ -n "$target_dependent_ports$target_dependent_ports_form2$target_required_ports$target_required_ports_form2" ]
then
	echo "INFO: Operations will be applied only to the targets:"
	if [ `cat "${DBDIR}"/target_dependent_ports.specified | wc -l` -gt 0 -a `cat "${DBDIR}"/target_required_ports.specified | wc -l` -gt 0 ]
	then
		echo "----------------------------------------"
		cat "${DBDIR}"/target_dependent_ports.specified
		echo "----------------------------------------"
		echo "and their dependents;"
		echo "----------------------------------------"
		cat "${DBDIR}"/target_required_ports.specified
		echo "----------------------------------------"
		echo "and their requirements."
		echo
	elif [ `cat "${DBDIR}"/target_dependent_ports.specified | wc -l` -gt 0 ]
	then
		echo "----------------------------------------"
		cat "${DBDIR}"/target_dependent_ports.specified
		echo "----------------------------------------"
		echo "and their dependents."
		echo
	elif [ `cat "${DBDIR}"/target_required_ports.specified | wc -l` -gt 0 ]
	then
		echo "----------------------------------------"
		cat "${DBDIR}"/target_required_ports.specified
		echo "----------------------------------------"
		echo "and their requirements."
		echo
	else
		echo  "ERROR: Target ports are specified but none of them is valid." >&2
		exit 1
	fi
fi

# Parse configuration file
if [ ! -e "${DBDIR}/COMPLETE_PARSE_CONF" ]
then
	echo "Start to parse configuration file [${APPNAME}.conf] at `timestamp`"
	(
		set -e
		_CONFVARS='ENV ALT_MOVED HOLD TABOO REPLACE_FROM REPLACE_TO MARG_TARGET MARG_DEF MENV_TARGET MENV_DEF BEFOREBUILD BEFOREDEINSTALL AFTERINSTALL'
		for item in ${_CONFVARS}
		do
			set | grep -e "^${item}_" | cut -d = -f 1 | sed 's/^/unset /'
		done > ${TMPDIR}/unsetvars.sh
		. "${TMPDIR}"/unsetvars.sh
		. "${DBDIR}"/setup.conf
		for item in ${_CONFVARS}
		do
			set | grep -e "^${item}_" | sed 's/^/_CONF_/'
		done > ${DBDIR}/confvars.sh
	) || { echo "ERROR: Invalid syntax in [${CONFFILE}]" >&2; exit 1; }
	touch "${DBDIR}/COMPLETE_PARSE_CONF"
fi
. "${DBDIR}/confvars.sh"

if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_1" ]
then
	echo "Starting to reflect settings of replacement defined in the configuration file at `timestamp`"
	echo PORTSDIR=${_CONF_ENV_PORTSDIR:-${PORTSDIR}} > "${DBDIR}/setenv.sh"
	echo DISTDIR=${_CONF_ENV_DISTDIR:-${DISTDIR:-${PORTSDIR}/distfiles}} >> "${DBDIR}/setenv.sh"
	
	if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_ALT_MOVED" ]
	then
		echo "-- ALT_MOVED_*"
		cp -p "${PORTS_MOVED_DB}" "${TMPDIR}/MOVED.conflist"
		set | grep -e '^_CONF_ALT_MOVED_' | cut -d = -f 1 | while read var
		do
			eval movedsb_path=\${$var}
			cat "$movedsb_path" >> ${DBDIR}/MOVED.conflist
		done
		touch "${DBDIR}/COMPLETE_REFLECTCONF_ALT_MOVED"
	fi
	if [ "${DBDIR}/MOVED.conflist" -nt "${PORTS_MOVED_DB}" ]
	then
		PORTS_MOVED_DB=${DBDIR}/MOVED.conflist
	fi
	
	build_conflist_target_list HOLD
	build_conflist_target_list TABOO
	combine_lists TABOO_PORTS.conflist taboo.list taboo.all.list
	
	if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_REPLACE" ]
	then
		echo "-- REPLACE_*"
		cp /dev/null "${DBDIR}/REPLACE.grep_from_pattern.conflist"
		cp /dev/null "${DBDIR}/REPLACE.replace_pattern.conflist"
		set | grep -e '^_CONF_REPLACE_FROM_' | cut -d = -f 1 | while read var
		do
			eval glob_pattern=\${$var}
			eval to=\${`echo $var | sed 's/^_CONF_REPLACE_FROM_/_CONF_REPLACE_TO_/'`}
			expand_glob_pattern_to_origins "$glob_pattern" yes > ${TMPDIR}/origins.2.tmp || :
			if [ `cat "${TMPDIR}/origins.2.tmp" | wc -l` -eq 0 ]
			then
				echo "WARNING: Original package to be replaced [$glob_pattern] is obsolete." >&2
				echo "      If still required, use a pattern for port origins instead." >&2
				continue
			fi
			str_escape_regexp_filter < ${TMPDIR}/origins.2.tmp | sed "s|^|^|; s|$|$|" >> ${DBDIR}/REPLACE.grep_from_pattern.conflist

			if [ -z "$to" -o "$to" = delete ]
			then
				to=
			else
				[ -d "${PORTSDIR}/$to" ] || echo "WARNING: replacement port [$to] is obsolete" >&2
			fi
			str_escape_regexp_filter < ${TMPDIR}/origins.2.tmp | sed "s|^|s:^|; s|$|$:$to:|" >> ${DBDIR}/REPLACE.replace_pattern.conflist
		done
		touch "${DBDIR}/COMPLETE_REFLECTCONF_REPLACE"
	fi
	touch "${DBDIR}/COMPLETE_REFLECTCONF_1"
fi
. "${DBDIR}/setenv.sh"

if [ ! -e "${DBDIR}/COMPLETE_REFLECTCONF_2" ]
then
	echo "Starting to reflect settings for each port defined in the configuration file at `timestamp`"
	build_conflist_target_val_pair MARG TARGET DEF
	build_conflist_target_val_pair MENV TARGET DEF
	build_conflist_target_val_pair BEFOREBUILD TARGET COMMAND
	build_conflist_target_val_pair BEFOREDEINSTALL TARGET COMMAND
	build_conflist_target_val_pair AFTERINSTALL TARGET COMMAND
	touch "${DBDIR}/COMPLETE_REFLECTCONF_2"
	echo
fi

# ------- Database construction -------

# Target ports
if [ ! -e "${DBDIR}/COMPLETE_INSTALLED_PORTS" ]
then
	echo "Starting to collect installed packages at `timestamp`"
	pkg_info_qoa 2> /dev/null > ${DBDIR}/installed_ports
	str_escape_regexp_filter < "${DBDIR}/installed_ports" | sed 's/^/^/; s/$/$/' > ${DBDIR}/installed_ports.grep_pattern
	touch "${DBDIR}/COMPLETE_INSTALLED_PORTS"
	echo
fi

if [ ! -e "${DBDIR}/COMPLETE_TARGETS" ]
then
	echo "Starting to check newly installing ports at `timestamp`"
	cp "${DBDIR}/installed_ports" "${DBDIR}/target_ports"
	cat "${DBDIR}/target_dependent_ports.specified" "${DBDIR}/target_required_ports.specified" 2> /dev/null | sort -u | add_lines_if_new "${DBDIR}"/target_ports
	touch "${DBDIR}/COMPLETE_TARGETS"
	echo
elif [ -e "${DBDIR}/REQUIRE_CHK_NEW_TARGET" ]
then
	echo "Starting to check newly installing ports at `timestamp`"
	cp "${DBDIR}/target_ports" "${DBDIR}/target_ports.new"
	sort -u "${DBDIR}/target_dependent_ports.specified" "${DBDIR}/target_required_ports.specified" | add_lines_if_new "${DBDIR}"/target_ports.new
	if [ `cat "${DBDIR}/target_ports" | wc -l` -ne `cat "${DBDIR}/target_ports.new" | wc -l` ]
	then
		echo "WARNING: The temporal database will be refreshed so as to reinstall the all failed ports and their dependents."
		rm -f "${DBDIR}/COMPLETE_COLLECED_ALL_DEPENDENCIES" \
			"${DBDIR}/COMPLETE_DISTFILES_LIST" \
			"${DBDIR}/COMPLETE_CONVERT_REQUIRES_LIST" \
			"${DBDIR}/COMPLETE_INSPECT_DEPENDENTS" \
			"${DBDIR}/COMPLETE_COPY_DEPENDENCY_TMPFILES" \
			"${DBDIR}/COMPLETE_ORDERED_ALL_DEPENDENCIES" \
			"${DBDIR}/COMPLETE_CHECKED_UNSATISFIED_DEPENDENCIES" \
			"${DBDIR}/COMPLETE_REFLECTCONF_2"
	fi
	echo
fi
rm -f "${DBDIR}/REQUIRE_CHK_NEW_TARGET"

# Inspection of all dependencies
if [ ! -e "${DBDIR}/COMPLETE_COLLECED_ALL_DEPENDENCIES" ]
then
	echo "Starting to inspect dependencies of the all installed packages at `timestamp`"
	[ -z "$target_dependent_ports$target_dependent_ports_form2$target_required_ports$target_required_ports_form2" ] || \
		echo "INFO: Ports irrelevant to the targets are also inspected in order to get complete information."
	[ -d "${DBDIR}/requires" ] || mkdir -p "${DBDIR}/requires"
	touch "${DBDIR}/moved_or_lost.list"
	touch "${DBDIR}/target.inspected.list"
	if [ -f "${DBDIR}/target_ports.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		cp -p "${DBDIR}/target_ports" "${DBDIR}/target_ports.remain"
	fi
	cp "${DBDIR}/target_ports.remain" "${TMPDIR}/target_ports"
	DEPTH_INDEX='--'
	nlines=`cat "${TMPDIR}/target_ports" | wc -l`
	iline=1
	while [ $iline -le $nlines ]
	do
		origin=`sed -n ${iline}p "${TMPDIR}/target_ports"`
		iline=$(($iline+1))
		inspect_dependencies "$origin"
		continue
	done
	touch "${DBDIR}/REPLACE.complete_replace_pattern.tmp"
	sort "${DBDIR}/REPLACE.complete_replace_pattern.tmp" | uniq > ${DBDIR}/REPLACE.complete_replace_pattern
	touch "${DBDIR}/COMPLETE_COLLECED_ALL_DEPENDENCIES"
	echo
fi

# Inspection of all required distfiles
if [ ! -e "${DBDIR}/COMPLETE_DISTFILES_LIST" -a $keep_distfiles = no ]
then
	echo "Starting to summarize distfiles list at `timestamp`"
	sort "${DBDIR}/distfiles.list" 2> /dev/null | uniq | str_escape_regexp_filter | sed 's|^|/|; s|$|$|' > ${DBDIR}/distfiles.grep.pattern || :
	touch "${DBDIR}/COMPLETE_DISTFILES_LIST"
	echo
fi

# Convert requires-lists to actual ones
if [ ! -e "${DBDIR}/COMPLETE_CONVERT_REQUIRES_LIST" ]
then
	echo "Starting conversion of requires-lists to actual ones at `timestamp`"
	if [ -f "${DBDIR}/convert_requires_lists.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/convert_requires_lists.remain
	fi
	cp "${DBDIR}/convert_requires_lists.remain" "${TMPDIR}/convert_requires_lists"
	while read dbpath
	do
		portname=`basename "$dbpath"`
		catpath=`dirname "$dbpath"`
		catname=`basename "$catpath"`
		origin=$catname/$portname
		sed -E -f "${DBDIR}/REPLACE.complete_replace_pattern" "$dbpath/requires" | grep -v '^$' | sort | uniq > $dbpath/requires.new
		mv "$dbpath/requires.new" "$dbpath/requires"
		sed -i '' 1d "${DBDIR}/convert_requires_lists.remain"
	done < ${TMPDIR}/convert_requires_lists
	touch "${DBDIR}/COMPLETE_CONVERT_REQUIRES_LIST"
	echo
fi

# Inspection of dependents
if [ ! -e "${DBDIR}/COMPLETE_INSPECT_DEPENDENTS" ]
then
	echo "Starting inspection of dependents at `timestamp`"
	if [ -f "${DBDIR}/inspect_dependent.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/inspect_dependent.remain
	fi
	cp "${DBDIR}/inspect_dependent.remain" "${TMPDIR}/inspect_dependent"
	while read dbpath
	do
		portname=`basename "$dbpath"`
		catpath=`dirname "$dbpath"`
		catname=`basename "$catpath"`
		origin=$catname/$portname
		sed "s|^|${DBDIR}/requires/|; s|$|/dependents|" "$dbpath/requires" | add_a_line_to_files_if_new "$origin"
		sed -i '' 1d "${DBDIR}/inspect_dependent.remain"
	done < ${TMPDIR}/inspect_dependent
	touch "${DBDIR}/COMPLETE_INSPECT_DEPENDENTS"
	echo
fi

# Preparation of matching patterns of dependencies
if [ ! -e "${DBDIR}/COMPLETE_PREPARATION_OF_MATCHING_PATTERNS_OF_DEPENDENCIES" ]
then
	echo "Starting preparation of matching patterns of dependencies at `timestamp`"
	if [ -f "${DBDIR}/prepare_matching_patterns_dependencies.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/prepare_matching_patterns_dependencies.remain
	fi
	cp "${DBDIR}/prepare_matching_patterns_dependencies.remain" "${DBDIR}/prepare_matching_patterns_dependencies"
	while read dbpath
	do
		portname=`basename "$dbpath"`
		catpath=`dirname "$dbpath"`
		catname=`basename "$catpath"`
		origin=$catname/$portname
		[ ! -e "${DBDIR}/requires/$origin/dependents" ] || str_escape_regexp_filter < ${DBDIR}/requires/$origin/dependents | sed 's/^/^/;s/$/$/' > ${DBDIR}/requires/$origin/dependents.pattern
		[ ! -e "${DBDIR}/initial/$origin/dependents" ] || str_escape_regexp_filter < ${DBDIR}/initial/$origin/dependents | sed 's/^/^/;s/$/$/' > ${DBDIR}/initial/$origin/dependents.pattern
		[ ! -e "${DBDIR}/requires/$origin/requires" ] || str_escape_regexp_filter < ${DBDIR}/requires/$origin/requires | sed 's/^/^/;s/$/$/' > ${DBDIR}/requires/$origin/requires.pattern
		[ ! -e "${DBDIR}/initial/$origin/requires" ] || str_escape_regexp_filter < ${DBDIR}/initial/$origin/requires | sed 's/^/^/;s/$/$/' > ${DBDIR}/initial/$origin/requires.pattern
		chk_if_target currentorigin "$origin"
		sed -i '' 1d "${DBDIR}/prepare_matching_patterns_dependencies.remain"
	done < ${DBDIR}/prepare_matching_patterns_dependencies
	touch "${DBDIR}/COMPLETE_PREPARATION_OF_MATCHING_PATTERNS_OF_DEPENDENCIES"
	echo
fi

# Preparation of matching patterns of obsolete ports to be deleted
if [ ! -e "${DBDIR}/COMPLETE_PREPARATION_OF_MATCHING_PATTERNS_OF_OBSOLETE_PORTS" ]
then
	echo "Starting preparation of matching patterns of obsolete ports to be deleted at `timestamp`"
	if [ -f "${DBDIR}/prepare_matching_patterns_obsolete_ports.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		cp -p "${DBDIR}/moved_or_lost.list" "${DBDIR}/prepare_matching_patterns_obsolete_ports.remain"
	fi
	cp "${DBDIR}/prepare_matching_patterns_obsolete_ports.remain" "${DBDIR}/prepare_matching_patterns_obsolete_ports"
	while read origin
	do
		chk_if_target currentorigin "$origin"
		sed -i '' 1d "${DBDIR}/prepare_matching_patterns_obsolete_ports.remain"
	done < ${DBDIR}/prepare_matching_patterns_obsolete_ports
	touch "${DBDIR}/COMPLETE_PREPARATION_OF_MATCHING_PATTERNS_OF_OBSOLETE_PORTS"
	echo
fi

# Inspection of necessary updates
if [ ! -e "${DBDIR}/COMPLETE_NECESSARY_UPDATES" ]
then
	echo "Starting inspection of necessary updates at `timestamp`"
	if [ -f "${DBDIR}/necessary_updates.remain" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/necessary_updates.remain
	fi
	cp "${DBDIR}/necessary_updates.remain" "${TMPDIR}/necessary_updates"
	while read dbpath
	do
		portname=`basename "$dbpath"`
		catpath=`dirname "$dbpath"`
		catname=`basename "$catpath"`
		origin=$catname/$portname
		if [ -e "${DBDIR}/requires/$origin/new_version" ]
		then
			touch "${DBDIR}/requires/$origin/necessary_update"
			if [ -e "${DBDIR}/requires/$origin/dependents" ]
			then
				while read origin_dependent
				do
					touch "${DBDIR}/requires/$origin_dependent/necessary_update"
				done < ${DBDIR}/requires/$origin/dependents
			fi
		fi
		sed -i '' 1d "${DBDIR}/necessary_updates.remain"
	done < ${TMPDIR}/necessary_updates
	touch "${DBDIR}/COMPLETE_NECESSARY_UPDATES"
	echo
fi

# Copying dependencies for preparation
if [ ! -e "${DBDIR}/COMPLETE_COPY_DEPENDENCY_TMPFILES" ]
then
	echo "Starting preparation for order of dependencies at `timestamp`"
	find "${DBDIR}/requires" -depth 3 -name requires -exec cp -p {} {}.remained \;
	touch "${DBDIR}/COMPLETE_COPY_DEPENDENCY_TMPFILES"
	echo
fi

# Clean up of reinstallation status for preparation
if [ -e "${DBDIR}/MODE_REDO" -a ! -e "${DBDIR}/COMPLETE_CLEANUP_REINST_STATUS" ]
then
	echo "Starting preparation for order of dependencies at `timestamp`"
	find "${DBDIR}/requires" -depth 3 -type d -name status -exec rm -rf {} \; -exec mkdir {} \;
	touch "${DBDIR}/COMPLETE_CLEANUP_REINST_STATUS"
	echo
fi

# Order the ports considering dependencies
if [ ! -e "${DBDIR}/COMPLETE_ORDERED_ALL_DEPENDENCIES" ]
then
	echo "Starting ordering of dependencies at `timestamp`"
	[ ! -f "${DBDIR}/reinst_order.list.tmp" ] || echo "INFO: Restarting from the previously terminated point"
	touch "${DBDIR}/reinst_order.list.tmp"
	cd "${DBDIR}/requires"
	cat > ${TMPDIR}/order_dependencies.awk << eof
BEGIN {
	it = 0;
	i = 0;
}
{
	if (NF == 0)
	{
		i = 0;
	}
	else
	{
		if (i == 0)
		{
			target = \$0;
			sub (/\/requires\.remained$/, "", target);
			sub (/^\.\//, "", target);
			srcikey[it] = target;
			srckeyi[target] = it;
			it++;
		}
		else
		{
			src[it-1,i-1] = \$0;
			srcimax[it-1] = srcsize[it-1] = i;
		}
		i++;
	}
}
END {
	ntargets = it;
	norder = 0;
	order_str = "";
	icycle = 0;
	lf_order_str = "";
	while (1)
	{
		is_operated = 0;
		for (it = 0; it < ntargets; it++)
		{
			if (!(it in srcikey)) continue;
			if (srcsize[it] > 0) continue;
			is_operated = 1;
			target = srcikey[it];
# 			print "[" icycle "]-- " target;
			delete srcikey[it];
			order[norder++] = target;
			order_str = order_str lf_order_str;
			order_str = sprintf ("%s%s", order_str, target);
			lf_order_str = "\n";
			for (jt = 0; jt < ntargets; jt++)
			{
				for (j = 0; j < srcimax[jt]; j++)
				{
					if ((jt,j) in src && src[jt,j] == target)
					{
						delete src[jt,j];
						srcsize[jt]--;
						break;
					}
				}
			}
		}
		if (is_operated == 0) break;
		icycle++;
	}
	reinst_order_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/reinst_order.list.tmp");
	print order_str > reinst_order_list;
	unsatisfied = "";
	for (it = 0; it < ntargets; it++)
	{
		if (srcsize[it] == 0) continue;
		reqs = "";
		sp_reqs = "";
		for (i = 0; i < srcimax[it]; i++)
		{
			if ((it,i) in src)
			{
				reqs = reqs ", " src[it,i];
				sp_reqs = ", ";
			}
		}
		unsatisfied = sprintf ("%s%s [%d] (%s)\n", unsatisfied, srcikey[it], srcsize[it], reqs);
	}
	if (unsatisfied != "")
	{
		unsatisfied_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/unsatisfied.list");
		print unsatisfied > unsatisfied_list;
		exit 1;
	}
}
eof
	find . -depth 3 -name requires.remained -exec echo {} \; -exec cat {} \; -exec echo \; | \
		env DBDIR=${DBDIR} awk -f "${TMPDIR}"/order_dependencies.awk || { \
			echo "ERROR: Unsatisfied dependencies are remained" >&2
			cat "${DBDIR}/unsatisfied.list"
			echo "*** Aborted by ${APPNAME}"
			echo "The ports tree seems broken. You might have caught an incomplete version."
			echo "You are encouraged to update the ports tree by portsnap(8)."
			echo "Then execute"
			echo " ${APPNAME} clean"
			echo "before restart."
			terminate_process ()
			{
			}
			exit 1
		}
	grep -v '^$' "${DBDIR}/reinst_order.list.tmp" > "${DBDIR}/reinst_order.list" || :
	touch "${DBDIR}/COMPLETE_ORDERED_ALL_DEPENDENCIES"
	rm -f "${TMPDIR}/targets"
	echo
fi

# Deinstallation of obsolete packages
if [ ! -e "${DBDIR}/COMPLETE_LIST_DEINST_OBS_PKGS" ]
then
	echo "Starting to compose a list of deinstallation of obsolete packages at `timestamp`"
	while read origin
	do
		origin_ptn=`str_escape_regexp ${origin}`
		[ `grep -m 1 -E "^${origin_ptn}$" "${DBDIR}/HOLD_PORTS.conflist" 2> /dev/null | wc -l` -gt 0 ] || echo $origin
	done < ${DBDIR}/moved_or_lost.list > ${DBDIR}/moved_or_lost.actual.list.tmp
	mv "${DBDIR}"/moved_or_lost.actual.list.tmp "${DBDIR}"/moved_or_lost.actual.list
	touch "${DBDIR}/COMPLETE_LIST_DEINST_OBS_PKGS"
	echo
fi

# ------- Main operations -------

if [ ! -e "${DBDIR}/COMPLETE_PREPARATION" ]
then
	touch "${DBDIR}/COMPLETE_PREPARATION"
fi

if [ "$command" = prepare ]
then
	echo "Done (skipped reinstallation) at `timestamp`"
	echo
	echo " You can restart this process from the aborted/terminated point by"
	echo "executing without options or arguments as:"
	echo "  ${APPNAME}"
	terminate_process ()
	{
	}
	exit
fi

terminate_process ()
{
	terminate_process_common
	terminate_process ()
	{
	}
}

# Deinstallation of obsolete packages
if [ ! -e "${DBDIR}/COMPLETE_DEINST_OBS_PKGS" ]
then
	_MSG_CURRENT_STAGE_general="deinstallation of obsolete packages"
	_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
	echo "Starting deinstallation of obsolete packages at `timestamp`"
	[ -d "${DBDIR}/backup_obsolete" ] || mkdir -p "${DBDIR}/backup_obsolete"
	[ -d "${DBDIR}/status_deinst" ] || mkdir -p "${DBDIR}/status_deinst"
	if [ `cat "${DBDIR}/moved_or_lost.list" | wc -l` -gt 0 ]
	then
		savedir=`pwd`
		if [ -f "${DBDIR}/moved_or_lost.list.remained" ]
		then
			echo "INFO: Restarting from the previously terminated point"
		else
			cp -p "${DBDIR}/moved_or_lost.list" "${DBDIR}/moved_or_lost.list.remained"
		fi
		cp -p "${DBDIR}/moved_or_lost.list.remained" "${TMPDIR}/moved_or_lost.tmp"
		nlines=`cat "${TMPDIR}/moved_or_lost.tmp" | wc -l`
		iline=1
		cd "${DBDIR}/backup_obsolete"
		while [ $iline -le $nlines ]
		do
			origin=`sed -n ${iline}p "${TMPDIR}/moved_or_lost.tmp"`
			iline=$(($iline+1))
			currentpkg=`pkg_info_qO "$origin" 2> /dev/null`
			[ -n "$currentpkg" ] || continue
			chk_if_target currentorigin "$origin"
			if [ -z "${currentorigin_is_relevant}" ]
			then
				echo "-- (Skipping an irrelevant package for obsolete port $origin as $currentpkg)"
				continue
			fi
			origin_ptn=`str_escape_regexp ${origin}`
			if [ `grep -m 1 -E "^${origin_ptn}$" "${DBDIR}/HOLD_PORTS.conflist" 2> /dev/null | wc -l` -gt 0 ]
			then
				echo "-- (Skipping a hold package for obsolete port $origin as $currentpkg)"
				continue
			fi
			_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
			echo "========== Starting deinstallation process for obsolete port $origin as $currentpkg =========="
			if [ -z "${currentorigin_is_all}" -a -n "${currentorigin_is_relevant}" ]
			then
				[ -z "${currentorigin_is_target}" ] || echo "(Target port)"
				[ -z "${currentorigin_is_dependent}" ] || echo "(Dependent of the target port(s))"
				[ -z "${currentorigin_is_required}" ] || echo "(Requirement of the target port(s))"
				[ -z "${currentorigin_is_former_dependent}" ] || echo "(Former dependent of the target port(s))"
				[ -z "${currentorigin_is_former_required}" ] || echo "(Former requirement of the target port(s))"
			fi
			echo "-- (Creating backup package for $origin as $currentpkg)"
			tag=`echo $origin | sed 's|/|.|'`
			if [ ! -e "${DBDIR}/status_deinst/$tag.backup" ]
			then
				pkg_create_b "$currentpkg" || { echo "*** Continuating forcibly by hoping success..."; continue; }
				touch "${DBDIR}/status_deinst/$tag.backup"
			fi
			echo "-- (Deleting package for $origin as $currentpkg)"
			pkg_delete_f "$currentpkg" || { echo "*** Continuating forcibly by hoping success..."; continue; }
			rm_a_line "$origin" "${DBDIR}/moved_or_lost.list.remained"
			_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
			echo
		done
		cd "$savedir"
	fi
	touch "${DBDIR}/COMPLETE_DEINST_OBS_PKGS"
	_MSG_CURRENT_STAGE=
	echo
fi

# Reinstallation of remained ports
[ ! -e "${DBDIR}/MODE_REDO" ] || rm -f "${DBDIR}/COMPLETE_REINSTALLATION" "${DBDIR}/COMPLETE_CLEANUP_OBSLETE_DISTFILES" "${DBDIR}/COMPLETE_REBUILD_PKGDB"
[ `cat "${DBDIR}/reinst_order.list" | wc -l` -gt 0 ] || touch "${DBDIR}/COMPLETE_REINSTALLATION"
if [ ! -e "${DBDIR}/COMPLETE_REINSTALLATION" ]
then
	_MSG_CURRENT_STAGE_general="reinstallation"
	_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
	echo "Starting reinstallation at `timestamp`"
	savedir=`pwd`
	mkdir "${TMPDIR}/backup"
	[ -d "${DBDIR}/backup_failure" ] || mkdir -p "${DBDIR}/backup_failure"
	if [ ! -e "${DBDIR}/MODE_REDO" -a -f "${DBDIR}/reinst_todo.list" ]
	then
		echo "INFO: Restarting from the previously terminated point"
	else
		cp -p "${DBDIR}/reinst_order.list" "${DBDIR}/reinst_todo.list"
	fi
	rm -f "${DBDIR}/MODE_REDO"
	cp -p "${DBDIR}/reinst_todo.list" "${TMPDIR}/reinst_todo.tmp"
	touch "${DBDIR}/failed.list"
	touch "${DBDIR}/success_but_dependencies_failed.list"
	touch "${DBDIR}/success.list"
	nlines_tot=$((`cat "${DBDIR}/reinst_order.list" | wc -l`))
	nlines=`cat "${TMPDIR}/reinst_todo.tmp" | wc -l`
	icount=$(($nlines_tot-$nlines))
	iline=1
	while [ $iline -le $nlines ]
	do
		_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
		origin=`sed -n ${iline}p "${TMPDIR}/reinst_todo.tmp"`
		iline=$(($iline+1))
		icount=$(($icount+1))
		MAKE_ARGS="FORCE_PKG_REGISTER=yes `[ $avoid_vulner = yes ] || echo DISABLE_VULNERABILITIES=yes` `cat "${DBDIR}/requires/$origin/MARG.conflist" 2> /dev/null || :`"
		MAKE_ENVS=`cat "${DBDIR}/requires/$origin/MENV.conflist" 2> /dev/null || :`
		counter="[$icount/$nlines_tot $(($icount*100/$nlines_tot))%]"
		if [ -e "${DBDIR}"/requires/$origin/new_version ]
		then
			newpkg=`cat "${DBDIR}"/requires/$origin/new_version`
		else
			newpkg=
		fi
		currentpkg=`pkg_info_qO "$origin" 2> /dev/null || :`
		if [ -n "$currentpkg" ]
		then
			origpkg=$currentpkg
		else
			origpkg=`cat "${DBDIR}/requires/$origin/backedup_version" 2> /dev/null || :`
		fi
		pkgtag=$origpkg
		[ -n "$pkgtag" ] || pkgtag=$newpkg
		if [ -z "$pkgtag" ]
		then
			pkgtag='?'
		
		elif [ -n "$newpkg" -a "x$currentpkg" != "x$newpkg" ]
		then
			if [ -n "$currentpkg" ]
			then
				pkgtag="$currentpkg => $newpkg"
			else
				pkgtag="[new] $newpkg"
			fi
		fi
		echo $pkgtag > ${DBDIR}/requires/$origin/pkgtag
		position_msg="$origin ($pkgtag)"
		if grep -m 1 -E "^`str_escape_regexp ${origin}`$" "${DBDIR}/success.list" 2> /dev/null > /dev/null
		then
			echo "========== $counter (Skipping an already reinstalled package for port $position_msg at `timestamp`) =========="
			echo
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		if [ $skip_unchanged = yes -a ! -e "${DBDIR}/requires/$origin/necessary_update" ]
		then
			echo "========== $counter (Skipping a port, $position_msg, because itself and the all of its requirements are already latest at `timestamp`) =========="
			echo
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		chk_if_target currentorigin "$origin"
		cp /dev/null "${TMPDIR}"/msg_if_target
		if [ -z "${currentorigin_is_all}" ]
		then
			if [ -n "${currentorigin_is_relevant}" ]
			then
				[ -z "${currentorigin_is_target}" ] || echo "(Target port)" > ${TMPDIR}/msg_if_target
				[ -z "${currentorigin_is_dependent}" ] || echo "(Dependent of the target port(s))" >> ${TMPDIR}/msg_if_target
				[ -z "${currentorigin_is_required}" ] || echo "(Requirement of the target port(s))" >> ${TMPDIR}/msg_if_target
				[ -z "${currentorigin_is_former_dependent}" ] || echo "(Former dependent of the target port(s))" >> ${TMPDIR}/msg_if_target
				[ -z "${currentorigin_is_former_required}" ] || echo "(Former requirement of the target port(s))" >> ${TMPDIR}/msg_if_target
			else
				echo "========== $counter (Skipping an irrelevant package for port $position_msg at `timestamp`) =========="
				echo
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				continue
			fi
		fi
		if grep -m 1 -E "^`str_escape_regexp ${origin}`$" "${DBDIR}/HOLD_PORTS.conflist" 2> /dev/null > /dev/null
		then
			echo "========== $counter (Skipping a hold package for port $position_msg at `timestamp`) =========="
			cat ${TMPDIR}/msg_if_target
			echo
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		if grep -m 1 -E "^`str_escape_regexp $origin`$" "${DBDIR}/taboo.all.list" 2> /dev/null > /dev/null
		then
			echo "========== $counter (Ignored a taboo port $position_msg at `timestamp`) =========="
			cat ${TMPDIR}/msg_if_target
			echo
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		if grep -m 1 -E "^`str_escape_regexp $origin`$" "${DBDIR}/manually_done.list" 2> /dev/null > /dev/null
		then
			echo "========== $counter (Marking a manually-done port $position_msg as success at `timestamp`) =========="
			cat ${TMPDIR}/msg_if_target
			echo
			record_success $origin
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		if [ -e "${DBDIR}/requires/$origin/SUPPRESSED" ]
		then
			echo "========== $counter (Skipping a suppressed port $position_msg as success at `timestamp`) =========="
			cat ${TMPDIR}/msg_if_target
			echo
			rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
			continue
		fi
		if [ -e "${DBDIR}/requires/$origin/installed_version" ]
		then
			insttarget=reinstall
			instdesc='a reinstallation'
		else
			insttarget=install
			instdesc='an installation'
		fi
		_MSG_CURRENT_STAGE="$instdesc process for $position_msg $counter"
		echo "========== $counter Starting $instdesc process for $position_msg at `timestamp` =========="
		cat ${TMPDIR}/msg_if_target
		cd "${PORTSDIR}/$origin"
		if [ -e "${DBDIR}/requires/$origin/status/in_build" ]
		then
			echo "(Restarting the previously terminated build process...)"
			flag_restarted_build=yes
		else
			touch "${DBDIR}/requires/$origin/status/in_build"
			flag_restarted_build=no
		fi
		if [ -e "${DBDIR}/requires/$origin/BEFOREBUILD.conflist" -a ! -e "${DBDIR}/requires/$origin/status/COMPLETE_BEFOREBUILD" ]
		then
			echo "-- BEFOREBUILD operations (start)"
			sh -e "${DBDIR}/requires/$origin/BEFOREBUILD.conflist" || \
			{
				echo "ERROR: while BEFOREBUILD operations for ${PORTSDIR}/$position_msg." >&2
				echo 'BEFOREBUILD operations' > ${DBDIR}/requires/$origin/note_failtre
				record_failure $origin noclean
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				cmt_fail_reinst "$origin"
				continue
			}
			echo "-- BEFOREBUILD operations (end)"
			touch "${DBDIR}/requires/$origin/status/COMPLETE_BEFOREBUILD"
		fi
		if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE_CLEAN_BEFORE_BUILD" ]
		then
			env ${MAKE_ENVS} make clean ${MAKE_ARGS} || \
			{
				echo "ERROR: Check the permission of directory ${PORTSDIR}/$position_msg." >&2
				echo 'clean before build' > ${DBDIR}/requires/$origin/note_failtre
				record_failure $origin noclean
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				cmt_fail_reinst "$origin"
				continue
			}
			echo
			touch "${DBDIR}/requires/$origin/status/COMPLETE_CLEAN_BEFORE_BUILD"
		fi
		if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE_FETCH" ]
		then
			if [ ! -e "${DBDIR}/requires/$origin/status/FAILED_FETCH" ]
			then
				if env ${MAKE_ENVS} make checksum ${MAKE_ARGS}
				then
					:
				else
					touch "${DBDIR}/requires/$origin/status/FAILED_FETCH"
				fi
			fi
			if [ -e "${DBDIR}/requires/$origin/status/FAILED_FETCH" ]
			then
				echo "WARNING: Refetching distfiles for ${PORTSDIR}/$position_msg." >&2
# 				if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE.FAILED_FETCH.DISTCLEAN" ]
# 				then
# 					env ${MAKE_ENVS} make distclean NOCLEANDEPENDS=yes ${MAKE_ARGS} || \
# 					{
# 						echo "ERROR: Failed in distclean for ${PORTSDIR}/$position_msg." >&2
# 						echo 'distclean for refetch' > ${DBDIR}/requires/$origin/note_failtre
# 						record_failure $origin
# 						rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
# 						cmt_fail_reinst "$origin"
# 						continue
# 					}
# 					touch "${DBDIR}/requires/$origin/status/COMPLETE.FAILED_FETCH.DISTCLEAN"
# 				fi
				if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE.FAILED_FETCH.REFETCH" ]
				then
					env ${MAKE_ENVS} make fetch ${MAKE_ARGS} FETCH_ARGS=-Ap || \
					{
						echo "ERROR: Failed in fetch for ${PORTSDIR}/$position_msg." >&2
						echo 'fetch' > ${DBDIR}/requires/$origin/note_failtre
						record_failure $origin
						rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
						cmt_fail_reinst "$origin"
						continue
					}
					env ${MAKE_ENVS} make checksum ${MAKE_ARGS} || \
					{
						echo "ERROR: Failed in checksum for ${PORTSDIR}/$position_msg." >&2
						echo 'checksum' > ${DBDIR}/requires/$origin/note_failtre
						record_failure $origin
						rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
						cmt_fail_reinst "$origin"
						continue
					}
					touch "${DBDIR}/requires/$origin/status/COMPLETE.FAILED_FETCH.REFETCH"
				fi
			fi
			touch "${DBDIR}/requires/$origin/status/COMPLETE_FETCH"
		fi
		if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE_BUILD" ]
		then
			if env ${MAKE_ENVS} make ${MAKE_ARGS}
			then
				:
			elif [ $flag_restarted_build = yes ]
			then
				rm "${DBDIR}/requires/$origin/status/COMPLETE_CLEAN_BEFORE_BUILD"
				echo "INFO: This failure may be due to restarting from a terminated build." >&2
				echo "WARNING: Retrying build after cleaning for ${PORTSDIR}/$position_msg." >&2
				env ${MAKE_ENVS} make clean ${MAKE_ARGS} || \
				{
					echo "ERROR: Check the permission of directory ${PORTSDIR}/$position_msg." >&2
					echo 'build and clean after build failure' > ${DBDIR}/requires/$origin/note_failtre
					record_failure $origin noclean
					rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
					cmt_fail_reinst "$origin"
					continue
				}
				if env ${MAKE_ENVS} make ${MAKE_ARGS}
				then
					:
				else
					echo 'build' > ${DBDIR}/requires/$origin/note_failtre
					record_failure $origin
					rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
					cmt_fail_reinst "$origin"
					continue
				fi
			else
				echo 'build' > ${DBDIR}/requires/$origin/note_failtre
				record_failure $origin
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				cmt_fail_reinst "$origin"
				continue
			fi
			touch "${DBDIR}/requires/$origin/status/COMPLETE_BUILD"
		fi
		rm -f "${DBDIR}/requires/$origin/status/in_build"
		if [ -e "${DBDIR}/requires/$origin/status/in_install" ]
		then
			echo "(Restarting the previously terminated installation process...)"
		else
			touch "${DBDIR}/requires/$origin/status/in_install"
		fi
		if [ -n "$currentpkg" -a ! -e "${DBDIR}/requires/$origin/status/COMPLETE_PKG_BACKUP" ]
		then
			echo "-- (Creating temporal backup package for $position_msg)"
			cd "${DBDIR}/backup_failure"
			pkg_create_b "$currentpkg" || \
			{
				rm -f "${DBDIR}/backup_failure/$currentpkg.tbz"
				echo "WARNING: Failed to create the backup package, but ignored by hoping success." >&2
			}
			cd "${PORTSDIR}/$origin"
			echo $currentpkg > ${DBDIR}/requires/$origin/backedup_version
			touch "${DBDIR}/requires/$origin/status/COMPLETE_PKG_BACKUP"
		fi
		if [ -n "$currentpkg" -a ! -e "${DBDIR}/requires/$origin/status/COMPLETE_BEFOREDEINSTALL" ]
		then
			if [ -e "${DBDIR}/requires/$origin/BEFOREDEINSTALL.conflist" ]
			then
				echo "-- BEFOREDEINSTALL operations (start)"
				sh -e "${DBDIR}/requires/$origin/BEFOREDEINSTALL.conflist" || \
				{
					echo "ERROR: while BEFOREDEINSTALL operations for ${PORTSDIR}/$position_msg." >&2
					echo 'BEFOREDEINSTALL operations' > ${DBDIR}/requires/$origin/note_failtre
					record_failure $origin noclean
					rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
					cmt_fail_reinst "$origin"
					continue
				}
				echo "-- BEFOREDEINSTALL operations (end)"
			fi
			touch "${DBDIR}/requires/$origin/status/COMPLETE_BEFOREDEINSTALL"
		fi
		if [ -n "$currentpkg" -a ! -e "${DBDIR}/requires/$origin/status/COMPLETE_DEINSTALL" ]
		then
			pkg_delete_f $currentpkg || \
			{
				echo "WARNING: Failed to deinstall $currentpkg by $command_pkg_delete." >&2
			}
			echo "-- (Trying to deinstall by ports to make sure. This usually ends up with warnings.)"
			env ${MAKE_ENVS} make deinstall ${MAKE_ARGS} || \
			{
				echo "WARNING: Failed to deinstall $currentpkg by make deinstall." >&2
			}
			touch "${DBDIR}/requires/$origin/status/COMPLETE_DEINSTALL"
		fi
		if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE_INSTALL" ]
		then
			if [ ! -e "${DBDIR}/requires/$origin/status/FAILED_INSTALL" ]
			then
				if env ${MAKE_ENVS} make $insttarget ${MAKE_ARGS}
				then
					touch "${DBDIR}/requires/$origin/status/COMPLETE_INSTALL"
				else
					touch "${DBDIR}/requires/$origin/status/FAILED_INSTALL"
				fi
			fi
			if [ -e "${DBDIR}/requires/$origin/status/FAILED_INSTALL" ]
			then
				if [ ! -e "${DBDIR}/requires/$origin/status/COMPETE.FAILED_INSTALL.RECOVER" ]
				then
					echo "*** Trying to deinstall the failed/terminated installation... (Ignore failures)"
					if [ -n "$currentpkg" ]
					then
						pkg_delete_f $currentpkg || :
					fi
					echo "*** Trying to deinstall by ports to make sure. (This usually ends up with warnings)"
					env ${MAKE_ENVS} make deinstall ${MAKE_ARGS} || :
					backedup_version=`cat "${DBDIR}/requires/$origin/backedup_version" 2> /dev/null || :`
					if [ -n "$backedup_version" ]
					then
						echo "*** Restoring the backup of $backedup_version..."
						if [ ! -e "${DBDIR}/backup_failure/$backedup_version.tbz" ]
						then
							echo "WARNING: No backup exists, gave up." >&2
						elif pkg_add_fF "${DBDIR}/backup_failure/$backedup_version.tbz"
						then
							:
						else
							echo "WARNING: Failed to restore $backedup_version. Note that your system may experience troubles by this error." >&2
						fi
					fi
					touch "${DBDIR}/requires/$origin/status/COMPETE.FAILED_INSTALL.RECOVER"
				fi
				if [ -n "$currentpkg" -a ! -e "${DBDIR}/requires/$origin/status/COMPETE.FAILED_INSTALL.AFTERINSTALL" -a -e "${DBDIR}/requires/$origin/AFTERINSTALL.conflist" ]
				then
					echo "-- AFTERINSTALL operations (start)"
					sh -e "${DBDIR}/requires/$origin/AFTERINSTALL.conflist" || { echo "-- (This error is ignored)"; }
					echo "-- AFTERINSTALL operations (end)"
					touch "${DBDIR}/requires/$origin/status/COMPETE.FAILED_INSTALL.AFTERINSTALL"
				fi
				echo 'install' > ${DBDIR}/requires/$origin/note_failtre
				record_failure $origin noclean
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				cmt_fail_reinst "$origin"
				continue
			fi
		fi
		if [ -e "${DBDIR}/requires/$origin/AFTERINSTALL.conflist" -a ! -e "${DBDIR}/requires/$origin/status/in_install.AFTERINSTALL" ]
		then
			echo "-- AFTERINSTALL operations (start)"
			sh -e "${DBDIR}/requires/$origin/AFTERINSTALL.conflist" || \
			{
				echo "ERROR: while AFTERINSTALL operations for ${PORTSDIR}/$position_msg." >&2
				echo 'AFTERINSTALL operations' > ${DBDIR}/requires/$origin/note_failtre
				record_failure $origin noclean
				rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
				cmt_fail_reinst "$origin"
				continue
			}
			echo "-- AFTERINSTALL operations (end)"
			touch "${DBDIR}/requires/$origin/status/in_install.AFTERINSTALL"
		fi
		if [ ! -e "${DBDIR}/requires/$origin/status/COMPLETE_CLEAN_AFTER_INSTALL" ]
		then
			env ${MAKE_ENVS} make clean ${MAKE_ARGS} || \
			{
				echo "WARNING: Failed to clean $position_msg." >&2
			}
			touch "${DBDIR}/requires/$origin/status/COMPLETE_CLEAN_AFTER_INSTALL"
		fi
		record_success $origin
		rm_a_line "$origin" "${DBDIR}/reinst_todo.list"
		rm -f "${DBDIR}/backup_failure/$currentpkg.tbz"
		rm "${DBDIR}/requires/$origin/status/in_install"
		_MSG_CURRENT_STAGE=${_MSG_CURRENT_STAGE_general}
		echo
	done
	cd "$savedir"
	touch "${DBDIR}/COMPLETE_REINSTALLATION"
	_MSG_CURRENT_STAGE=
	echo
fi

# Clean up obsolete or unused distfiles
if [ ! -e "${DBDIR}/COMPLETE_CLEANUP_OBSLETE_DISTFILES" ]
then
	echo "Starting to clean up obsolete or unused distfiles at `timestamp`"
	find "${DISTDIR}" -type f | grep -v -E -f "${DBDIR}/distfiles.grep.pattern" | while read distfile
	do
		echo "  $distfile"
		rm -f "$distfile"
	done
	touch "${DBDIR}/COMPLETE_CLEANUP_OBSLETE_DISTFILES"
	echo
fi

# Rebuild of package database
if [ ! -e "${DBDIR}/COMPLETE_REBUILD_PKGDB" ]
then
	if which -s pkgdb
	then
		echo "Starting to rebuild package database for portupgrade at `timestamp`"
		pkgdb -fu
	fi
	touch "${DBDIR}/COMPLETE_REBUILD_PKGDB"
	echo
fi

# Notice of failures
touch "${DBDIR}/failed.list"
if [ `cat "${DBDIR}/failed.list" | wc -l` -gt 0 ]
then
	echo "*** (Re)installation of the following ports were unsuccessful."
	echo " Please recover them manually."
	echo " You are recommended to read ${PORTSDIR}/UPDATING to resolve the problems."
	echo "If you have installed ports-mgmt/portupgrade or ports-mgmt/portupgrade-devel,"
	echo "pkg_updating(1) will be useful for this purpose."
	echo " You can check whether the failed ports are already unnecessary"
	echo "by executing"
	echo "        ${APPNAME} show dependents [failed_port_globs]"
	echo " For unnecessary failed ports, you can delete it by"
	echo "        $command_pkg_delete -f [failed_port_globs]"
	echo "and then execute"
	echo "        ${APPNAME} taboo add [deleted_port_globs]"
	echo " For necessary and manually successful ports, after resolving the problems,"
	echo "execute"
	echo "        ${APPNAME} ok add [resolved_port_globs]"
	echo "and restart by"
	echo "        ${APPNAME} redo"
	echo "****************"
	show_list_failure
	echo "*** Warned by ${APPNAME}"
	echo
fi

# End
terminate_process ()
{
}

echo "All done at `timestamp`"
