#!/bin/bash
#
#############################################################################
#
# tukbuild is meant to make it easier to write SlackBuild-like
# scripts which build software from source and package it.
#
# The latest version of tukbuild can be found from
# <ftp://ftp.tukaani.org/tukaani/source/tools/>.
#
# Currently there is no other documentation than the comments in this script.
#
#############################################################################
#
# The GNU tools required to run tukbuild are included in Slackware 10.0 and
# later. Here's a list of required software and _minimum_ supported versions:
#  - GNU bash 2.05b (3.x is recommended because it detects errors from pipes.)
#  - GNU coreutils 5.2.1
#  - GNU sed 4.xx
#  - GNU grep 2.5
#  - GNU findutils 4.1.7
#  - getopt from util-linux 2.12a
#  - GNU wget 1.9.x (only if something is downloaded)
#  - GNU or HJL binutils (for the strip command)
#  - file 4.xx (to detect which files to strip)
#  - GCC 3.x.x
#  - gzip 1.2.4
#  - bzip2 1.0.x
#  - Slackware 10.0 pkgtools, or Tukaani pkgtools tukaani_1.0.0
#  - LZMA Utils 4.32.0beta1 (optional)
#  - gconftool-2 (optional, used in _gconf())
#
#############################################################################
#
# Copyright (C) 2005, 2006, 2007 Lasse Collin <lasse.collin@tukaani.org>
# Copyright (C) 2006 Zeqadious <zeqadious@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
#############################################################################
#
# Last modified: 2007-05-03
_TUKBUILD_VERSION_MAJOR=2
_TUKBUILD_VERSION_MINOR=38
#
#############################################################################


###############
# shopt flags #
###############
# This must be before functions.
shopt -s dotglob extglob extquote
shopt -u sourcepath

# Fail if any part in a pipe fails. This is supported only by bash >=3.
[ -n "${BASH_VERSINFO[0]}" -a "${BASH_VERSINFO[0]}" -ge 3 ] && set -o pipefail


####################
# Helper functions #
####################
# These functions are intended to be used only internally by tukbuild.
# Of course, nothing prevents you from using these from your TukBuild
# file, but it is generally discouraged.

# Check if $1 is a non-negative integer.
_is_number() {
	[[ $1 == +([0-9]) ]]
}

# Many commands interpret integer argument as a source/path/packagedir
# number, and non-integers as filename or pathname. _expand_arg makes
# this simple by detecting the argument type and settings RETURN_VALUE
# appropriately. Like all the arrays in bash, we start indexing from zero.
# $1 = integer or something else ;)
# $2... = expanded values if $1 is an integer.
_expand_arg() {
	if _is_number "$1"; then
		shift "$1"
		shift 1
	fi
	if [ -z "$1" ]; then
		echo '+ ERROR: Invalid parameter.'
		exit 1
	fi
	RETURN_VALUE=$1
	return 0
}

_upgradepkg() {
	if type -P spkg &> /dev/null; then
		spkg "$@"
	else
		upgradepkg "$@"
	fi
}

_removepkg() {
	if type -P spkg &> /dev/null; then
		spkg -d "$@"
	else
		removepkg "$@"
	fi
}

# Downloads a SOURCE or PATCH file to DISTFILES directory and verifies
# MD5 and SHA1 checksums.
_download() {
	local URL FILE MD5 SHA1
	URL=$1
	FILE=$(basename "$1")
	MD5=$2
	SHA1=$3
	RETURN_VALUE=
	if [ -f "$CWD/$FILE" ]; then
		echo "+   $FILE found in $CWD"
		RETURN_VALUE="$CWD/$FILE"
	elif [ -f "$DISTFILES/$FILE" ]; then
		echo "+   $FILE found in $DISTFILES"
		RETURN_VALUE="$DISTFILES/$FILE"
	elif _is_url "$URL"; then
		# Check that we have an URL where to download:
		echo "+   $FILE not found, trying to download."
		_wget "$URL" "$DISTFILES/$FILE"
		RETURN_VALUE="$DISTFILES/$FILE"
	elif _is_url "$CWD_URL"; then
		# No URL was specified in TukBuild file but we have URL to
		# the TukBuild file. Try to download from the same directory
		# where the TukBuild file is:
		echo "+   $FILE not found, trying to download."
		_wget "$CWD_URL/$URL" "$DISTFILES/$FILE"
		RETURN_VALUE="$DISTFILES/$FILE"
	else
		echo "+ File not found and no download URL" \
				"specified: $FILE"
		exit 1
	fi
	# Check the checksum(s):
	if [ -n "$MD5" -a "$MD5" != "-" ]; then
		echo "+     Verifying MD5 sum of $FILE"
		if [ "$(md5sum < "$RETURN_VALUE" | cut -f 1 -d ' ')" \
				!= "$MD5" ]; then
			echo '+ ERROR: Verification of MD5 sum failed.'
			exit 1
		fi
	fi
	if [ -n "$SHA1" -a "$SHA1" != "-" ]; then
		echo "+     Verifying SHA1 sum of $FILE"
		if [ "$(sha1sum < "$RETURN_VALUE" | cut -f 1 -d ' ')" \
				!= "$SHA1" ]; then
			echo '+ ERROR: Verification of SHA1 sum failed.'
			exit 1
		fi
	fi
}

# Helper for _doc_except().
_doc_except_helper_func() {
	local I J
	for I in ANNOUNCE AUTHORS BUGS CHANGELOG ChangeLog COPYING* \
			INSTALL LICENSE HISTORY NEWS README* TODO USAGE
		do (
		for J; do
			# If match, continue to next file:
			[ "$I" = "$J" ] && exit 0
		done
		# Don't copy zero size files:
		[ -s "$I" -o ! -f "$I" ] && echo "$I"
	); done
}

# Create a package.
_makepkg() {
	local PKGDIR PKGFILE PKGINFO I J K
	_expand_arg "$1" "${PKG[@]}"
	PKGDIR=$RETURN_VALUE
	PKGFILE=$2
	echo "+ _makepkg $PKGDIR -> $PKGFILE"
	if [ ! -d "$PKGDIR" ]; then
		echo "+ ERROR: Directory does not exists: $PKGDIR"
		exit 1
	fi
	cd "$PKGDIR"
	echo '+ Processing documentation files.'
	# The info directory file, locale.alias and perllocal.pod should never
	# exists in a normal package (info/dir can be in textinfo and
	# locale.alias is in glibc and perllocal.pod in perl):
	_docfix "$PKGDIR" # _docfix needs to be before the "rm" below.
	rm -f ".$INFODIR"/dir{,.gz} usr/{,local/}share/locale/locale.alias \
			usr/{,local/}lib*/perl5/5.*/*/perllocal.pod
	rmdir -p --ignore-fail-on-non-empty usr/{,local/}lib*/perl5/5.*/* \
		> /dev/null 2> /dev/null
	# Man page fixes:
	for K in usr{,/local,/X11{,R{6,7}}}{,/share}/man opt/*/{share/,}man; do
		if [ -d "$K" -a ! -L "$K" ]; then
			# Instead of having many small files that have only
			# '.so' command we create symlinks. Note that this
			# loop assumes that filenames don't have $IFS-chars.
			for I in $(find "$K" -mindepth 2 \
					-type f ! -size +128c); do
				J=$(sed -n 's,^.*/\([^/ ]*\) *$,\1,p' "$I")
				# Simple error check:
				[ "$J" = "" ] && continue
				rm -f "$I"
				ln -sf "$J" "$I"
			done
			if [ "$COMPRESS_MAN" = "1" ]; then
				# Fix symlinks:
				for I in $(find "$K" -mindepth 2 \
						-type l ! -name '*.gz'); do
					J=$(readlink "$I")
					rm -f "$I"
					ln -sf "$J.gz" "$I.gz"
				done
				# Compress. ": | gzip" trick forces gzip to
				# work non-interactively i.e. never ask if
				# a file should be overwritten (never
				# overwrite). Cannot use -f because it
				# would destroy symlinks.
				: | gzip -9rn "$K" 2> /dev/null
			fi
		fi
	done
	# Compress GNU info pages:
	[ "$COMPRESS_MAN" = "1" -a -d ".$INFODIR" ] \
			&& : | gzip -9rn ".$INFODIR" 2> /dev/null
	# Fix possibly wrong permissions:
	for I in ".$MANDIR" ".$INFODIR"; do
		if [ -d "$I" ]; then
			find "$I" -type f -print0 | xargs -0r chmod 0644 --
			find "$I" -type d -print0 | xargs -0r chmod 0755 --
		fi
	done
	# Strip binaries:
	if [ "$STRIP" = "1" ]; then
		# This breaks if filenames have spaces (or newlines):
		echo '+ Stripping binaries and libraries.'
		find . -type f -print0 | xargs -0r file -- | sed -n \
			's/^\(.*\):.* ELF .* executable, .*, not stripped$/\1/p' \
			| tr '\n' '\0' \
			| xargs -0r strip --strip-all --
		find . -type f -print0 | xargs -0r file -- | sed -n \
			's/^\(.*\):.* ELF .* shared object, .*, not stripped$/\1/p' \
			| tr '\n' '\0' \
			| xargs -0r strip --strip-unneeded --
		find . -type f -print0 | xargs -0r file -- | sed -n \
			's/^\(.*\):.* ELF .* relocatable, .*, not stripped$/\1/p' \
			| tr '\n' '\0' \
			| xargs -0r strip --strip-debug --
		find . -type f -name '*.a' -print0 | xargs -0r file -- \
			| sed -n 's/^\(.*\): *current ar archive$/\1/p' \
			| tr '\n' '\0' \
			| xargs -0r strip --strip-debug --
	fi
	# Put the package description in place (slack-desc). We don't
	# overwrite any slack-desc files, the build script might have
	# generated it (e.g. because of version number dependent content).
	PKGINFO=0
	if [ ! -f install/slack-desc ] && _is_number "$1"; then
		[ "$DISTRO" = 'vector' ] && PKGINFO=1
		echo "+ Searching for file ${NAME[$1]}.desc."
		for J in "$CWD/${NAME[$1]}.desc" \
				"$CWD/${NAME[$1]}.desc"; do
			if [ -f "$J" ]; then
				echo "+ Creating" \
					"${PKG[$1]}/install/slack-desc from $J."
				cat "$J" | _desc "$1" quiet
				break
			fi
		done
	fi
	# slack-required, slack-conflicts and slack-suggests:
	for K in required conflicts suggests; do
		if [ ! -f install/slack-$K ] && _is_number "$1"; then
			echo "+ Searching for file ${NAME[$1]}.$K."
			for J in "$CWD/${NAME[$1]}.$K" \
					"$CWD/${NAME[$1]}.$K"; do
				if [ -f "$J" ]; then
					echo "+ Copying $J to " \
						"${PKG[$1]}/install/slack-$K."
					mkdir -p install # Should exist already.
					cat "$J" > install/slack-$K
					break
				fi
			done
		fi
	done
	if [ ! -f install/slack-desc ]; then
		echo "+ WARNING: $PKGDIR/install/slack-desc"
		echo "+          doesn't exist and no .desc file" \
				"for it was not found."
	# Append Vector-specific stuff to slack-desc:
	elif [ "$PKGINFO" = '1' ]; then
		cat <<- EOF >> install/slack-desc

		----------------------------------------
		BUILDDATE : $(date)
		PACKAGER  : $([[ $PACKAGER_NAME ]] && echo "$PACKAGER_NAME" || echo "$USER")
		HOST      : $(uname -srm)
		DISTRO    : $({ cat /etc/vector-version \
				|| cat /etc/slackware-version \
				|| echo '(Unknown)'; } 2> /dev/null)
		CFLAGS    : $CFLAGS
		CONFIG    : ${_CONFIGURE_FLAGS}
		EOF
	fi
	# Finally make the package:
	echo "+ Creating the package file: $PKGFILE"
	# Slackware has this only in /sbin:
	/sbin/makepkg --prepend -c n -l y "$PKGFILE"
}

_cleanup() {
	if [ "$CLEANUP" = "1" ]; then
		if [ -f /var/log/packages/zzz_tukbuild_temp-$$-unknown-0tukbuild ]; then
			echo '+ Removing temporary package.'
			_removepkg zzz_tukbuild_temp-$$-unknown-0tukbuild
		fi
		echo '+ Removing temporary files.'
		rm -rf "$TMP"
	fi
}

_show_version() {
	echo "${_TUKBUILD_VERSION_MAJOR}.${_TUKBUILD_VERSION_MINOR}"
}

_show_usage() {
	cat << EOF

tukbuild version ${_TUKBUILD_VERSION_MAJOR}.${_TUKBUILD_VERSION_MINOR}

tukbuild is a tool used to build binary packages from TukBuild files.
Currently tukbuild supports only systems having Slackware(R) compatible
pkgtools and basic GNU tools installed.

Usage:  tukbuild [options] [TukBuild files...]

  -a, --arch <arch>           Build package for architechture <arch>
  -b, --build <build>         Build tag
  -d, --distro <distro>       Build for (and on) distribution (autodetected)
  -j, --jobs <jobs>           Number of parallel jobs
  -c, --command <cmd>         Run function/command(s) <cmd> instead of build()
  -S, --no-strip              Do not strip binaries, same as STRIP=0
  -C, --no-cleanup            Do not remove temporary files, same as CLEANUP=0
      --scripts-to-package    Copy build scripts into pkg (default on Zenwalk)
      --no-scripts-to-package Do not copy build scripts into the package.
      --name-prefix           Prefix NAME with PREFIXTYPE (default on Base).
      --no-name-prefix        Do not prefix package NAME with PREFIXTYPE.
  -h, --help                  Show this help screen
  -V, --version               Show only version number

If no TukBuild files are given, all files in the current directory having
the suffix \`.TukBuild' will be built. You can also give HTTP or FTP URL
to pointing to a TukBuild file.

To learn how to write new TukBuild files, see the comments in the tukbuild
script and skim a few example .TukBuild files. Currently there is no better
documentation available

EOF
	exit 0
}

_prefix_helper_prefixes() {
# $1 = PREFIXTYPE (optional)
	PREFIXTYPE=${PREFIXTYPE:-normal}
	[ -n "$1" ] && PREFIXTYPE=$1
	echo "+ Setting PREFIXTYPE=$PREFIXTYPE"
	# Slackware 11.1 moved X and KDE to /usr. Cope with that.
	case $DISTRO in
		slackware|slamd64)
			if egrep -qs ' (10|11\.0)' /etc/slackware-version \
					/etc/slamd64-version; then
				case $PREFIXTYPE in
					x11|kde) PREFIXTYPE=normal ;;
				esac
			fi
		;;
	esac
	case "$ARCH-$DISTRO-$PREFIXTYPE" in
		*-tukaani-normal|*-tukaani-x11) # Modular X.org goes to /usr
			PREFIX=/usr
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var
			# We decided to switch from Slackware-like locations
			# to FHS. Symlinks are kept in the distro so should be
			# no problem for those who are used to old locations.
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-tukaani-qt3|*-tukaani-qt4)
			PREFIX=/opt/$PREFIXTYPE
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc
			LOCALSTATEDIR=$PREFIX/var
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-tukaani-gnome)
			PREFIX=/opt/gnome
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			# FHS would say /etc/opt/gnome and /var/opt/gnome
			# but we disagree.
			SYSCONFDIR=$PREFIX/etc
			LOCALSTATEDIR=$PREFIX/var
			# These follow FHS 2.3. FHS 2.2 instructed to use
			# $PREFIX/{info,man,doc} in /opt.
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-tukaani-kde)
			# See the comments for *-tukaani-gnome above.
			PREFIX=/opt/kde
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc
			LOCALSTATEDIR=$PREFIX/var
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-tukaani-games)
			PREFIX=/usr
			BINDIR=$PREFIX/games
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share/games
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var/games
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-slackware-normal|*-vector-normal|*-vector-x11)
			PREFIX=/usr
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var
			# Doesn't follow recent FHS but I won't argue
			# which one is better, FHS or Slack way:
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=$PREFIX/doc
			;;
		*-slackware-x11)
			PREFIX=/usr/X11R6
			BINDIR=$PREFIX/bin
			SBINDIR=/usr/sbin # Not used with x11?
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc # ???
			LOCALSTATEDIR=/var
			INFODIR=/usr/info
			MANDIR=$PREFIX/man
			DOCDIR=/usr/doc
			;;
		*-slackware-kde|*-vector-kde)
			PREFIX=/opt/kde
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc
			LOCALSTATEDIR=$PREFIX/var
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=/usr/doc
			;;
		*-slackware-games|*-vector-games)
			PREFIX=/usr
			BINDIR=$PREFIX/games
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share/games
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var/games
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=$PREFIX/doc
			;;
		x86_64-slamd64-normal)
			PREFIX=/usr
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib64
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var
			# Slackware-like locations:
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=$PREFIX/doc
			;;
		x86_64-slamd64-kde)
			PREFIX=/opt/kde
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib64
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc
			LOCALSTATEDIR=$PREFIX/var
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=/usr/doc
			;;
		x86_64-slamd64-games)
			PREFIX=/usr
			BINDIR=$PREFIX/games
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib64
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share/games
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var/games
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=$PREFIX/doc
			;;
		*-zenwalk-normal|*-zenwalk-kde|*-zenwalk-gnome|*-zenwalk-x11)
			PREFIX=/usr
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var
			INFODIR=$PREFIX/info
			MANDIR=$PREFIX/man
			DOCDIR=$PREFIX/doc
			;;
		*-zenwalk-games)
			PREFIX=/usr/games
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var/games
			INFODIR=/usr/info
			MANDIR=/usr/man
			DOCDIR=/usr/doc
			;;
		*-base-normal|*-base-x11)
			PREFIX=/usr
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=/etc
			LOCALSTATEDIR=/var
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		*-base-*)
			PREFIX=/opt/$PREFIXTYPE
			BINDIR=$PREFIX/bin
			SBINDIR=$PREFIX/sbin
			LIBDIR=$PREFIX/lib
			LIBEXECDIR=$PREFIX/libexec
			INCLUDEDIR=$PREFIX/include
			DATADIR=$PREFIX/share
			SYSCONFDIR=$PREFIX/etc
			# We will follow FHS in this (at least a little),
			# because it makes it easier for multi-partitions
			# systems where /var is usually a seperate partition.
			LOCALSTATEDIR=/var/$PREFIXTYPE
			INFODIR=$DATADIR/info
			MANDIR=$DATADIR/man
			DOCDIR=$DATADIR/doc
			;;
		custom)
			;;
		*)
			echo "+ Unknown PREFIXTYPE: $PREFIXTYPE"
			exit 1
			;;
	esac
}

# Set CONFIGURE to contain appropriate command and flags. It was idiotic
# to have a variable for this job, but this is kept here for backwards
# compatibility. Use _configure instead of $CONFIGURE.
_prefix_helper_configure() {
	CONFIGURE="./configure \
		--prefix=$PREFIX \
		--bindir=$BINDIR \
		--sbindir=$SBINDIR \
		--libexecdir=$LIBEXECDIR \
		--datadir=$DATADIR \
		--sysconfdir=$SYSCONFDIR \
		--localstatedir=$LOCALSTATEDIR \
		--libdir=$LIBDIR \
		--includedir=$INCLUDEDIR \
		--infodir=$INFODIR \
		--mandir=$MANDIR \
		--program-prefix= \
		--program-suffix= \
		--build=$CONFIGURE_TRIPLET \
		--cache-file=$TMP/configure.cache"
}


########################
# "Exported" functions #
########################
# These functions are intended to be used by TukBuild files.

# This is useful on Vector to store configure flags when finishing an aborted
# build process. Just replace call to _configure with _configure_flags.
_configure_flags() {
	_CONFIGURE_FLAGS=$(echo \
		--prefix=$PREFIX \
		--bindir=$BINDIR \
		--sbindir=$SBINDIR \
		--libexecdir=$LIBEXECDIR \
		--datadir=$DATADIR \
		--sysconfdir=$SYSCONFDIR \
		--localstatedir=$LOCALSTATEDIR \
		--libdir=$LIBDIR \
		--includedir=$INCLUDEDIR \
		--infodir=$INFODIR \
		--mandir=$MANDIR \
		--program-prefix= \
		--program-suffix= \
		--build=$CONFIGURE_TRIPLET \
		"$@")
}

# Runs the configure scripts created by GNU Autoconf.
_configure() {
	# Grab the configure flags which can be stored to the slack-desc
	# as a hidden part.
	_configure_flags "$@"
	# Run configure.
	./configure \
		--prefix=$PREFIX \
		--bindir=$BINDIR \
		--sbindir=$SBINDIR \
		--libexecdir=$LIBEXECDIR \
		--datadir=$DATADIR \
		--sysconfdir=$SYSCONFDIR \
		--localstatedir=$LOCALSTATEDIR \
		--libdir=$LIBDIR \
		--includedir=$INCLUDEDIR \
		--infodir=$INFODIR \
		--mandir=$MANDIR \
		--program-prefix= \
		--program-suffix= \
		--build=$CONFIGURE_TRIPLET \
		--cache-file=$TMP/configure.cache \
		"$@"
}

# Explode an archive. If $1 is an integer, ${SOURCE[$1]} is exploded;
# otherwise $1 should be a filename. If you want to explode the archive
# to somewhere else than $TMP, you can specify the target directory as
# the second argument.
# $1 = Integer for SOURCE or a filename
# $2 = Target path, if omitted defaults to $TMP.
_explode() {
	local FILE TARGET
	# If we have been given at maximum of three characters as the first
	# argument, assume that it is the index number of source file.
	# The indexing starts from 0.
	_expand_arg "$1" "${SOURCE[@]}"
	FILE=$RETURN_VALUE
	[ -z "$2" ] && TARGET=$TMP || TARGET=$2
	echo "+ _explode $FILE -> $TARGET"
	mkdir -p "$TARGET" || exit $?
	case "$FILE" in
		*.tar)            tar xf "$FILE" -C "$TARGET" ;;
		*.tar.gz|*.tgz)   gzip -cd "$FILE" | tar xf - -C "$TARGET" ;;
		*.tar.bz2|*.tbz)  bzip2 -cd "$FILE" | tar xf - -C "$TARGET" ;;
		*.tar.lzma|*.tlz) lzma d -si -so < "$FILE" 2> /dev/null \
		                          | tar xf - -C "$TARGET" ;;
		*.zip)            unzip -o "$FILE" -d "$TARGET" ;;
		*.cpio)           ( cd "$TARGET"; cpio -id ) < "$FILE" ;;
		# TODO: rpm2cpio could be replaced.
		*.rpm)            ( cd "$TARGET"
		                      rpm2cpio | cpio -id ) < "$FILE" ;;
		*.gz)             gzip -cd "$FILE" > \
		                      "$TARGET/$(basename "$TARGET" .gz)" ;;
		*.bz2)            bzip2 -cd "$FILE" > \
		                      "$TARGET/$(basename "$TARGET" .bz2)" ;;
		*.lzma)           lzma -cd "$FILE" > \
		                      "$TARGET/$(basename "$TARGET" .lzma)" ;;
		*)                echo "+ WARNING: Unknown file type," \
		                            "skipping: $FILE";;
	esac
}

# Shortcut to explode all the SOURCE archives to $TMP.
_explode_all() {
	local I
	for (( I=0; I < ${#SOURCE[@]}; I++ )); do
		_explode $I
	done
}

# The preferred way to set CFLAGS and CXXFLAGS is to use OPTIMIZE
# variable. However, sometimes it is nice to change flags in the middle
# of the TukBuild. configure.cache has be removed every time flags are
# changed or else the next configure script will complain.
_cflags() {
	rm -f "$TMP/configure.cache"
	export CFLAGS="${_CPUFLAGS} $*"
	export CXXFLAGS=$CFLAGS
	export GCJFLAGS=$CFLAGS
}

# Check if $1 is an URL (HTTP, HTTPS or FTP).
_is_url() {
	# =~ is not supported by bash 2.05b, neither is
	# [[ $1 == foo* -o $1 == bar* ]] but this works:
	[[ $1 == http://*/* ]] \
			|| [[ $1 == https://*/* ]] \
			|| [[ $1 == ftp://*/* ]] \
			|| [[ $1 == svn://*/* ]]
}

# This was originally a wrapper for wget, but later it got support for
# svn too. This removes the target file if wget exists unsuccessfully
# or it is aborted by the user.
# $1 = URL
# $2 = Target filename
_wget() {
	(
		set +e
		trap "rm -f \"$2\"" INT TERM
		echo "+ _wget: $1 -> $2"
		if [[ $1 == svn://*/* ]]; then
			# This is probably broken. Suggestions are welcome.
			svn co "$1" "$2"
		else
			wget $WGET_FLAGS -O "$2" "$1"
		fi
		if [ $? = 0 ]; then
			echo '+ Download successful.'
		else
			rm -f "$2"
			echo "+ ERROR: Downloading $(basename "$2") failed."
			exit 1
		fi
	)
}

# Reset permissions: chown everything to root:root (actually using UID
# and GID 0), chmod all the directories to 0755, all the files with any
# exectuble bit set to 0755 and the rest to 0644. _chfix always operates
# recursively. You can specify which directories _chfix will modify.
# If no arguments are given, the default is to fix all package
# directories (${PKG[@]}).
_chfix() {
	if [ "x$1" = "x--quiet" ]; then
		shift
	else
		echo "+ _chfix $*"
	fi
	if [ $# = 0 ]; then
		set -- "${PKG[@]}"
	else
		_expand_arg "$1" "${PKG[@]}"
		set -- "$RETURN_VALUE"
	fi
	[ "$UID" = "0" ] && chown -hR 0:0 -- "$@"
	find "$@" ! -type l -type d -print0 | xargs -0r chmod 0755 --
	find "$@" ! -type l ! -type d -perm +0111 -print0 \
			| xargs -0r chmod 0755 --
	find "$@" ! -type l ! -type d ! -perm +0111 -print0 \
			| xargs -0r chmod 0644 --
}

# Slackware and Slamd64 follow an ancient standard that says that all
# binaries in bin and sbin directories and the directories themselves
# should be owned by group bin instead of root. Always make sure you
# handle this one way or another. With most packages it is simples to
# have _chgrp_bin right after _chfix. Be careful with _chgrp_bin because
# if you have any setuid binaries the setuid bits will be turned off at
# least on Linux. The arguments for _chgrp_bin are given similarly to _chfix.
_chgrp_bin() {
	local I J
	if [ "$CHGRP_BIN" = "1" -a "$UID" = "0" ]; then
		if [ $# = 0 ]; then
			for J in "${PKG[@]}"; do
				echo "+ _chgrp_bin (default dirs in $J)"
				for I in {,usr/,usr/local/,opt/*/}{bin,sbin}; do
					[ -e "$J/$I" ] && chgrp -R bin "$J/$I"
				done
			done
		else
			echo "+ _chgrp_bin $*"
			for I; do
				_expand_arg "$I" "${PKG[@]}"
				[ -e "$RETURN_VALUE" ] && \
						chgrp -R bin "$RETURN_VALUE"
			done
		fi
	else
		echo '+ _chgrp_bin (skipping)'
	fi
	# return 0 is important here. Otherwise we might return with
	# non-zero exit status and stop the build process.
	return 0
}

# Apply a patch. If $1 is an integer, it is interpreted as ${PATCH[$1]},
# otherwise it should be a patch file (possibly compressed).
# $1 = Integer for PATCH array, or patch filename
# $2 ... = Options to be passed to the patch command
_patch() {
	local FILE
	_expand_arg "$1" "${PATCH[@]}"
	FILE=$RETURN_VALUE
	shift 1
	echo "+ _patch $FILE $*"
	case "$FILE" in
		*.gz)             gzip -cd "$FILE" | patch "$@" ;;
		*.bz2)            bzip2 -cd "$FILE" | patch "$@" ;;
		*.lzma)           lzma -cd "$FILE" | patch "$@" ;;
		*)                patch "$@" < "$FILE" ;;
	esac
}

# Copy documentation files.
# $1 = Integer for PKG array, or path to package root directory
# $2 = Directory name in the documentation directory
# $3 ... = Files to be copied
# Example: To copy README and COPYING to $PKG$DOCDIR/$NAME-$VERSION use
# a command like this: _doc 0 $NAME-$VERSION  README COPYING
# The target directory is automatically created if it doesn't exist.
_doc() {
	local I J
	if [ $# -lt 2 ]; then
		echo '+ ERROR: _doc requires at least two arguments.'
		exit 1
	fi
	_expand_arg "$1" "${PKG[@]}"
	J="$RETURN_VALUE$DOCDIR/$2"
	shift 2
	echo "+ _doc $* -> $J"
	for I; do
		# Not copying empty files:
		[ -f "$I" -a ! -s "$I" ] && continue
		if [ -e "$I" -o -L "$I" ]; then
			[ ! -d "$J" ] && mkdir -p "$J"
			cp -av "$I" "$J"
			_chfix --quiet "$J/${I##*/}"
		fi
	done
}

# Copy documentation files that have commonly used names except listed files.
# $1 = Integer for PKG array, or path to package root directory
# $2 = Directory name in the documentation directory
# $3 ... = Files to be *excluded*
# These files are copied from the current directory:
#     ANNOUNCE AUTHORS BUGS CHANGELOG ChangeLog COPYING*
#     INSTALL LICENSE HISTORY NEWS README* TODO USAGE
_doc_except() {
	if [ $# -lt 2 ]; then
		echo '+ ERROR: _doc_except requires at least two arguments.'
		exit 1
	fi
	local PKGDIR DIRNAME
	_expand_arg "$1" "${PKG[@]}"
	PKGDIR=$RETURN_VALUE
	DIRNAME=$2
	shift 2
	echo "+ _doc_except $* -> ${PKGDIR}${DOCDIR}/$DIRNAME"
	_doc "$PKGDIR" "$DIRNAME" $(_doc_except_helper_func "$@")
}

# Remove empty directories. If no arguments are given, all the package
# directories (${PKG[@]}) are scanned and empty directories removed.
# Be careful with this command if you have used _tmp_pkg since there
# might be directories that contain only symlinks, but symlinks are
# moved to doinst.sh; _rm_empty_dirs doesn't detect those.
_rm_empty_dirs() {
	local I
	[ $# = 0 ] && set -- "${PKG[@]}"
	echo "+ _rm_emptry_dirs $*"
	for I; do
		_expand_arg "$I" "${PKG[@]}"
		if [ ! -d "$RETURN_VALUE" ]; then
			echo "+ ERROR: Directory doesn't exist: $RETURN_VALUE"
			exit 1
		fi
		find "$RETURN_VALUE" -type d \
				| xargs rmdir -pv --ignore-fail-on-non-empty --
	done
	# Avoid non-zero exit status:
	return 0
}

# Create a temporary package and install it to the system. You should have
# specified ROOT_REQUIRED=1 in the toplevel of the TukBuild file. Make sure
# you have reasonable permissions in the package directory before using
# _tmp_pkg e.g. use _chfix and _chgrp_bin first.
# $1 = Integer for PKG, or a directory to be _makepkg'ed and upgradepkg'ed.
# $2 = "keep-symlinks" or empty.
_tmp_pkg() {
	(
		_expand_arg "$1" "${PKG[@]}"
		if [ ! -d "$RETURN_VALUE" ]; then
			echo "+ ERROR: Directory doesn't exist: $RETURN_VALUE"
			exit 1
		fi
		echo "+ Creating temporary package from $RETURN_VALUE"
		# Check if we have Tukaani pkgtools:
		if [ "$HAS_TUKAANI_MAKEPKG" = "1" ]; then
			PKGTYPE=tar
		else
			PKGTYPE=tgz
		fi
		PKGFILE="$TMP/zzz_tukbuild_temp-$$-unknown-0tukbuild.$PKGTYPE"
		PKGDIR=$RETURN_VALUE
		if [ "$2" = "keep-symlinks" ]; then
			PKGDIR="$TMP/zzz_tukbuild_temp-$$"
			rm -rf "$PKGDIR"
			cp -al "$RETURN_VALUE" "$PKGDIR"
		fi
		# Some things may return errors that are safe to ignore:
		set +e
		_makepkg "$PKGDIR" "$PKGFILE" || exit $?
		_upgradepkg --reinstall --install-new "$PKGFILE" || exit $?
		[ "$2" = "keep-symlinks" ] && rm -rf "$PKGDIR"
		: # Return with successful exit status.
	)
}

# Move documentation files to correct directories by using some force.
# Sometimes packages put info, man and/or doc directories e.g. to /usr/doc
# when you would like to have them in /usr/share/doc (or vice versa). This
# function will fix that. This is run automatically by _makepkg() but
# in some relatively rare situations you might need to run it separately too.
# $1 ... = Package directories to be fixed; if omitted, defaults to all the
#          package directories (${PKG[@]}).
_docfix() {
	local I J K
	if [ $# = 0 ]; then
		set -- "${PKG[@]}"
	else
		_expand_arg "$1" "${PKG[@]}"
		set -- "$RETURN_VALUE"
	fi
	echo "+ _docfix $*"
	# Fix documentation locations, if needed. E.g. either
	# /usr/{doc,man,info} or /usr/share/{doc,man,info}.
	for K; do
		for J in "$DOCDIR" "$MANDIR" "$INFODIR"; do
			for I in "$PREFIX"/{,local/}{,share/}"$(basename "$J")"; do
				if [ "$I" != "$J" -a -d "$K$I" ]; then
					# Using cp is better because mv refuses
					# to move files if the destination
					# already exists (or am I missing
					# something here?).
					mkdir -p "$K$J"
					cp -af "$K$I"/* "$K$J"
					rm -rf "$K$I"
					# Remove now possibly empty directory:
					rmdir -p --ignore-fail-on-non-empty \
							"$(dirname "$K$I")"
				fi
			done
		done
	done
}

# It is not nice to overwrite configuration files. _new will append
# an extension .new to the filenames and put a config_new() function
# to doinst.sh which will conditionally rename the files to their
# real names.
# $1 = Integer for PKG, or package root directory
# $2 ... = List of files to be renamed.
_new() {
	local PKGDIR I
	_expand_arg "$1" "${PKG[@]}"
	PKGDIR=$RETURN_VALUE
	if [ ! -d "$PKGDIR" ]; then
		echo "+ ERROR: Directory does not exist: $PKGDIR"
		exit 1
	fi
	shift 1
	echo "+ _new $PKGDIR: $*"
	if ! grep -q '^config_new() {$' "$PKGDIR/install/doinst.sh" \
			> /dev/null 2> /dev/null; then
		echo '+ Adding the config_new() function to ./install/doinst.sh.'
		mkdir -p "$PKGDIR/install"
		[ -e "$PKGDIR/install/doinst.sh" ] && mv -f \
				"$PKGDIR/install/doinst.sh" \
				"$PKGDIR/install/doinst.sh.tmp"
		cat << "EOF" > "$PKGDIR/install/doinst.sh"
config_new() {
	# If there's no config file by that name, mv it over:
	if [ ! -e "$1" ]; then
		mv -f "$1.new" "$1"
	# Using 'md5sum' instead of 'cmp' to compare files, because it
	# is possible that the diffutils package is not installed:
	elif [ "$(md5sum < "$1")" = "$(md5sum < "$1.new")" ]; then
		# Remove the redundant copy:
		rm -f "$1.new"
	fi
	# Otherwise, we leave the .new copy for the admin to consider...
}

EOF
		if [ -e "$PKGDIR/install/doinst.sh.tmp" ]; then
			cat "$PKGDIR/install/doinst.sh.tmp" \
				>> "$PKGDIR/install/doinst.sh"
			rm -f "$PKGDIR/install/doinst.sh.tmp"
		fi
	fi
	# Then the actual config commands:
	for I; do
		# Remove a prefixed slash, if any. This makes
		#     _new 0 $SYSCONFDIR/foo.conf
		# work, which previously needed to be:
		#     _new 0 ${SYSCONFDIR#/}/foo.conf
		I=${I#/}
		if [ ! -f "$PKGDIR/$I" ]; then
			echo "+ File doesn't exist: $PKGDIR/$I"
			exit 1
		fi
		mv -f "$PKGDIR/$I" "$PKGDIR/$I.new"
		echo "config_new '$(echo "$I" | sed "s/'/'\\\\''/g")'" \
				>> "$PKGDIR/install/doinst.sh"
	done
}

# Same as _new but the file is deleted if it cannot be renamed to its real
# name when installing. Handy if you don't want to leave unneeded .new files
# to users systems.
_new_delete() {
	local PKGDIR I J
	_expand_arg "$1" "${PKG[@]}"
	PKGDIR=$RETURN_VALUE
	shift 1
	echo "+ _new_delete $PKGDIR $*"
	for I; do
		I=${I#/}
		_new "$PKGDIR" "$I"
		J="${I//"'"/"'\\''"}.new"
		echo "[ -e '$J' ] && rm -f '$J'" \
				>> "$PKGDIR/install/doinst.sh"
	done
}

# User can override _prefix() in tukbuildrc.
_prefix() {
	_prefix_helper_prefixes "$@"
	_prefix_helper_configure
}

# Because of weirdness in Slackware's way to specify description, you need
# to give the basename of the package as the second argument if and only
# if you use directory name instead of package number.
_desc() {
	if ! _is_number "$1"; then
		echo '+ ERROR: _desc can be used only with a package number.'
		exit 1
	fi
	_expand_arg "$1" "${PKG[@]}"
	[ "$2" != "quiet" ] && echo "+ _desc $RETURN_VALUE/install/slack-desc"
	[ ! -d "$RETURN_VALUE/install" ] && mkdir -p "$RETURN_VALUE/install"
	# Prefix every line with "$BASENAME: " and replace certain strings
	# in the description. This should allow Zenwalkers to use .desc files
	# instead of embedding everything in the .TukBuild file:
	sed "
		s|^|$NAMEPREFIX${NAME[$1]}: |
		s|@NAME@|${NAME[$1]}|g
		s|@VERSION@|${VERSION[$1]}|g
		" > "$RETURN_VALUE/install/slack-desc"
	# Add PACKAGER_TAG as the 13th line of the description,
	# if there is enough space:
	local LINE_COUNT=$(wc -l < "$RETURN_VALUE/install/slack-desc" | tr -d ' ')
	if [ -n "$PACKAGER_TAG" -a $LINE_COUNT -lt 13 ]; then
		while [ $LINE_COUNT -lt 12 ]; do
			echo "$NAMEPREFIX${NAME[$1]}: " \
					>> "$RETURN_VALUE/install/slack-desc"
			LINE_COUNT=$((LINE_COUNT + 1))
		done
		echo "$NAMEPREFIX${NAME[$1]}: $PACKAGER_TAG" \
				>> "$RETURN_VALUE/install/slack-desc"
	fi
}

# _suggests()
# _conflicts()

# $1 = Integer for PKG array, or path to package root directory
# $2 = GCONF_CONFIG_SOURCE; this argument is optional. The default
#      value: $SYSCONFDIR/gconf/gconf.xml.defaults
_gconf() {
	if [ $# -lt 1 ]; then
		echo '+ ERROR: _gconf requires at least one argument.'
		exit 1
	fi
	_expand_arg "$1" "${PKG[@]}"

	# If we haven't been given a custom path for GCONF_CONFIG_SOURCE,
	# use the default:
	if [ -z "$2" ]; then
		export GCONF_CONFIG_SOURCE="xml::$RETURN_VALUE$SYSCONFDIR/gconf/gconf.xml.defaults"
	else
		export GCONF_CONFIG_SOURCE="xml::$RETURN_VALUE$2"
	fi

	echo "+ _gconf $GCONF_CONFIG_SOURCE"

	# Remove redundant scrollkeeper.
	if [ -d "$RETURN_VALUE$LOCALSTATEDIR/scrollkeeper" ]; then
		rm -rf "$RETURN_VALUE$LOCALSTATEDIR/scrollkeeper"
	fi
	if [ -d "$RETURN_VALUE$LOCALSTATEDIR/lib/scrollkeeper" ]; then
		rm -rf "$RETURN_VALUE$LOCALSTATEDIR/lib/scrollkeeper"
	fi

	# Setup default install rules.
	if [ -d "$RETURN_VALUE$SYSCONFDIR/gconf/schemas" ]; then
		mkdir -p "$RETURN_VALUE$SYSCONFDIR/gconf/gconf.xml.defaults"

		local I
		for I in "$RETURN_VALUE$SYSCONFDIR/gconf/schemas"/*.schemas; do
			if [ -e "$I" ]; then
				gconftool-2 --makefile-install-rule "$I"
			fi
		done

		for I in "$RETURN_VALUE$SYSCONFDIR/gconf/schemas"/*.entries; do
			if [ -e "$I" ]; then
				gconftool-2 --direct \
					--config-source="$GCONF_CONFIG_SOURCE" \
					--load "$I"
			fi
		done

		# Reset / Verify correct permissions
		find "$RETURN_VALUE$SYSCONFDIR/gconf" -type d -print0 \
				| xargs -0r chmod 0755 --
		find "$RETURN_VALUE$SYSCONFDIR/gconf" -type f -print0 \
				| xargs -0r chmod 0644 --
	fi

	unset GCONF_CONFIG_SOURCE
}


# Adds dynamically generated dependency information to the package
# (creates slack-required). Alternative (and usually more comfortable way)
# is to use file packagename.required.
# $1 = Integer for PKG, or package directory name
# The data written to dependency information file should be given via stdin
# in identical format that is used in slack-required files.
_required() {
	_expand_arg "$1" "${PKG[@]}"
	echo "+ _required $RETURN_VALUE/install/slack-required"
	[ ! -d "$RETURN_VALUE/install" ] && mkdir -p "$RETURN_VALUE/install"
	cat > "$RETURN_VALUE/install/slack-required"
}

###################
# Initializations #
###################

# This cannot be overriden via environment:
unset BUILD_COMMAND

# Parse command line arguments
_ARGS=$(getopt -n tukbuild -o a:b:c:d:j:CSDhV \
		-l arch:,build:,command:,distro:,jobs:,optimize \
		-l no-cleanup,no-strip,download-only,help,version \
		-l scripts-to-package,no-scripts-to-package \
		-l name-prefix,no-name-prefix -- "$@")
[ $? != 0 ] && exit 99
eval set -- "${_ARGS}"
unset _ARGS
while :; do
	case "$1" in
		-a|--arch)                  ARCH=$2; shift ;;
		-b|--build)                 BUILD=$2; shift ;;
		-d|--distro)                DISTRO=$2; shift ;;
		-c|--command)               BUILD_COMMAND=$2; shift ;;
		-j|--jobs)                  MAKEJOBS=$2; shift ;;
		-o|--optimize)              OPTIM=$2; shift ;;
		-C|--no-cleanup)            CLEANUP=0 ;;
		-S|--no-strip)              STRIP=0 ;;
		   --scripts-to-package)    SCRIPTS_TO_PACKAGE=1 ;;
		   --no-scripts-to-package) SCRIPTS_TO_PACKAGE=0 ;;
		   --name-prefix)           NAME_WITH_PREFIXTYPE=1 ;;
		   --no-name-prefix)        NAME_WITH_PREFIXTYPE=0 ;;
		-D|--download-only)         DOWNLOAD_ONLY=1 ;;
		-h|--help)                  _show_usage; exit 0 ;;
		-V|--version)               _show_version; exit 0 ;;
		--)                         shift; break ;;
		*)                          echo '+ Bug in command line' \
		                                    'parsing code.'
		                            exit 99
		                            ;;
	esac
	shift
done

# We didn't show help or version, so let's say hello:
echo "+ tukbuild version" \
	"${_TUKBUILD_VERSION_MAJOR}.${_TUKBUILD_VERSION_MINOR}"

###################
# DISTRO and ARCH #
###################
# - DISTRO determines
#     + the default package format (tgz or tlz)
#     + if the directories bin and sbin should be owned by the bin group
#     + if info and man pages should be gzipped.
# - ARCH determines the -march and -mtune/-mcpu values in CFLAGS/CXXFLAGS.
# - DISTRO-ARCH combination determines the value of CONFIGURE_TRIPLET.

# Detect DISTRO:
if [ -z "$DISTRO" ]; then
	if [ -f /etc/tukaani-version ]; then
		DISTRO=Tukaani
	elif [ -f /etc/zenwalk-version ]; then
		DISTRO=Zenwalk
	elif [ -f /etc/base-version ]; then
		DISTRO=Base
	elif [ -f /etc/vector-version ]; then
		DISTRO=Vector
	elif [ -f /etc/slamd64-version ]; then
		DISTRO=Slamd64
	elif [ -f /etc/slackware-version ]; then
		if [ "$(uname -m)" = "x86_64" ]; then
			DISTRO=Slamd64
		else
			DISTRO=Slackware # Or similar enough
		fi
	else
		echo '+ Autodetecting the distribution failed. Please set the'
		echo '+ DISTRO environment variable manually. Supported values'
		echo '+ for DISTRO (case-insensitive):'
		echo '+ Slackware Slamd64 Tukaani Zenwalk Base Vector'
	fi
	echo "+ DISTRO=$DISTRO (autodetected)"
else
	echo "+ DISTRO=$DISTRO (manually specified)"
fi
DISTRO=$(echo "$DISTRO" | tr A-Z a-z)  # Force lower case

# Detect ARCH:
if [ -z "$ARCH" ]; then
	case "$(uname -sm)" in
		'Linux i386')  ARCH=i386 ;; # No one should have this. ;-P
		'Linux i486')  ARCH=i486 ;; # Neither this for building.
		'Linux i586')
			case "$DISTRO" in
				tukaani|base|vector) ARCH=i586 ;;
				*)                   ARCH=i486 ;;
			esac
			;;
		'Linux i686')
			case "$DISTRO" in
				tukaani|vector)  ARCH=i586 ;;
				base)            ARCH=i686 ;;
				*)               ARCH=i486 ;;
			esac
			;;
		'Linux x86_64') ARCH=x86_64 ;;
		*) echo '+ Autodetecting ARCH failed. Please set ARCH' \
		        '+ environment variable manually.'
		   echo '+ Supported values for ARCH:'
		   echo '+ i386 i486 i586 i686 athlon athlonxp pentium2' \
		        'pentium3 pentium4 x86_64 noarch'
		   exit 1 ;;
	esac
	echo "+ ARCH=$ARCH (autodetected)"
else
	echo "+ ARCH=$ARCH (manually specified)"
fi
ARCH=$(echo "$ARCH" | tr A-Z a-z)  # Force lower case

# Set -march and -mtune:
case "$ARCH" in
	i386)         _CPUFLAGS="-march=i386 -mtune=i686" ;;
	i486)         _CPUFLAGS="-march=i486 -mtune=i686" ;;
	i586)         _CPUFLAGS="-march=i586 -mtune=i686" ;;
	i686)         _CPUFLAGS="-march=i686 -mtune=i686" ;;
	athlon)       _CPUFLAGS="-march=athlon -mtune=athlon" ;;
	athlonxp)     _CPUFLAGS="-march=athlon-xp -mtune=athlon-xp" ;;
	pentium2)     _CPUFLAGS="-march=pentium2 -mtune=pentium2" ;;
	pentium3)     _CPUFLAGS="-march=pentium3 -mtune=pentium3" ;;
	pentium4)     _CPUFLAGS="-march=pentium4 -mtune=pentium4" ;;
	x86_64)       _CPUFLAGS="-fPIC" ;;
	noarch)       _CPUFLAGS="" ;;
	*)            echo "+ Uknown ARCH: $ARCH"; exit 1 ;;
esac
# GCC 3.3 and older use -mcpu instead of -mtune:
gcc --version | head -n1 | grep -q ' \(3\.4\|4\.\)' \
		|| _CPUFLAGS=${_CPUFLAGS//-mtune=/-mcpu=}

# General initializations and settings:
umask 0022
[ -z "$UID" ] && UID=$(id -u)
[ -z "$GID" ] && GID=$(id -g)
_TUKBUILD_TOOL="$(cd -- "$(dirname -- "$0")"; pwd)/${0##*/}"
TMP=${TMP:-"$TMPDIR"}
TMP=${TMP:-/tmp}
DISTFILES=${DISTFILES:-"$PWD"}
PACKAGES=${PACKAGES:-"$PWD"}
WGET_FLAGS=${WGET_FLAGS:-"--passive-ftp --tries=3 --timeout=15"}
CWD_URL=
STRIP=${STRIP:-1}
CLEANUP=${CLEANUP:-1}
DOWNLOAD_ONLY=${DOWNLOAD_ONLY:-0}
ROOT_REQUIRED=${ROOT_REQUIRED:-0}
MAKEJOBS=${MAKEJOBS:-1}
NUMJOBS=$MAKEJOBS # Backwards compatibility
NUMOBJS=$MAKEJOBS # and typocompatibility ;-)
BUILD_COMMAND=${BUILD_COMMAND:-build} # Cannot be overriden via environment.
BUILDPREFIX= # This gets prefixed to $BUILD.

# Mirrors, probably more in the future:
MIRROR_SF=${MIRROR_SF:-http://dl.sf.net}
MIRROR_KDE=${MIRROR_KDE:-ftp://ftp.kde.org/pub/kde}
MIRROR_GNOME=${MIRROR_GNOME:-http://ftp.gnome.org/pub/gnome/sources}
MIRROR_GNU=${MIRROR_GNU:-ftp://ftp.gnu.org/pub/gnu}

# Reset these before reading the config since user might have custom prefixes:
unset PREFIX BINDIR SBINDIR LIBDIR LIBEXECDIR INCLUDEDIR DATADIR \
		SYSCONFDIR LOCALSTATEDIR INFODIR MANDIR DOCDIR

# Read config file:
if [ -f "$HOME/.tukbuildrc" ]; then
	echo "+ Reading $HOME/.tukbuildrc."
	source "$HOME/.tukbuildrc"
elif [ -f /etc/tukbuildrc ]; then
	echo '+ Reading /etc/tukbuildrc.'
	source /etc/tukbuildrc
fi

echo '+ Verifying basic variables and paths:'
for J in "TMP" "DISTFILES" "PACKAGES"; do
	I=${!J}
	if [ ! -d "$I" -o ! -r "$I" -o ! -w "$I" ]; then
		echo "+   $J=$I: Not a directory or no read-write access allowed."
		exit 1
	fi
	echo "+   $J=$I"
done
unset J

# Most packages can be compiled as non-root because all the
# files including binaries can be owned by root:root:
CHGRP_BIN=0
# Compressing man pages saves space when installed, but increases size of
# packages. Maybe in future the package manager can compress the man pages
# when packages are installed. ;-)
COMPRESS_MAN=1
CONFIGURE_TRIPLET=
case "$DISTRO" in
	slackware)
		PKGFORMAT=${PKGFORMAT:-tgz}
		# String that can be passed to configure:
		case "$ARCH" in
			i386)
				CONFIGURE_TRIPLET=i386-slackware-linux ;;
			i?86|athlon|athlonxp|pentium[234])
				CONFIGURE_TRIPLET=i486-slackware-linux ;;
		esac
		# Starting from Slack 11.0, the ancient habbit to chgrp
		# all binaries to the bin group is no longer used. Since
		# tukbuild doesn't support older Slackware versions than
		# 10.0, this check should be enough to detect if CHGRP_BIN=1
		# should be set.
		fgrep -qs ' 10.' /etc/slackware-version && CHGRP_BIN=1
		;;
	slamd64)
		PKGFORMAT=${PKGFORMAT:-tgz}
		CONFIGURE_TRIPLET=x86_64-slackware-linux
		fgrep -qs ' 10.' /etc/slackware-version /etc/slamd64-version \
				&& CHGRP_BIN=1
		;;
	tukaani)
		# Let's make smaller packages. :-)
		PKGFORMAT=${PKGFORMAT:-tlz}
		# String that can be passed to configure:
		case "$ARCH" in
			i386|i486)
				echo '+ Tukaani for i386 and i486 is not supported.' \
						'Use at least ARCH=i586.'
				sleep 3
				;;
			i?86|athlon|athlonxp|pentium[234])
				CONFIGURE_TRIPLET=i586-tukaani-linux-gnu ;;
		esac
		;;
	zenwalk)
		PKGFORMAT=${PKGFORMAT:-tgz}
		CONFIGURE_TRIPLET=i486-slackware-linux
		SCRIPTS_TO_PACKAGE=${SCRIPTS_TO_PACKAGE:-1}
		# Starting from Zenwalk 4.0, the build tag contains the
		# version number for which the package has been built.
		if [ -f /etc/zenwalk-version ] && ! grep -qs \
				'^Zenwalk [0-3]\.' /etc/zenwalk-version; then
			BUILDPREFIX=$(sed -rn 's|^Zenwalk ([0-9]+)\.([0-9]+).*$|\1\2|p;q' \
					/etc/zenwalk-version).
		fi
		;;
	base)
		PKGFORMAT=${PKGFORMAT:-tlz}
		CONFIGURE_TRIPLET=i686-base-linux
		NAME_WITH_PREFIXTYPE=${NAME_WITH_PREFIXTYPE:-1}
		;;
	vector)
		PKGFORMAT=${PKGFORMAT:-tlz}
		CONFIGURE_TRIPLET=i486-slackware-linux
		if [[ -z $PACKAGER_NAME ]]; then
			echo '+ WARNING: The variable PACKAGER_NAME is not set. You should set it'
			echo '           in /etc/tukbuildrc or ~/.tukbuildrc to match the nick you'
			echo '           use on the VectorLinux forum.'
			sleep 3
		fi
		;;
	*)
		echo "+ ERROR: Unknown distribution: $DISTRO"
		exit 1
		;;
esac


# For non-Zenwalk:
SCRIPTS_TO_PACKAGE=${SCRIPTS_TO_PACKAGE:-0}

# For non-Base:
NAME_WITH_PREFIXTYPE=${NAME_WITH_PREFIXTYPE:-0}

# Detect type of makepkg.
if /sbin/makepkg --help | fgrep -qs Tukaani; then
	HAS_TUKAANI_MAKEPKG=1
else
	HAS_TUKAANI_MAKEPKG=0
fi

if [ "$UID" != "0" ]; then
	# Show a small warning if we are running on Slackware or Slamd64
	# which require chgrp'ing executables to the bin group:
	if [ "$CHGRP_BIN" = "1" ]; then
		echo "+ WARNING: Running as non-root." \
				"This is not supported on $DISTRO."
		sleep 3
	fi
	# Another warning if Slackware's makepkg is used as non-root.
	# It doesn't support setting ownerships to root:root like
	# Tukaani's makepkg.
	if [ "$HAS_TUKAANI_MAKEPKG" = "0" ]; then
		echo "+ WARNING: Running as non-root. This is not" \
				"supported with Slackware's makepkg."
		sleep 3
	fi
fi


#############################
# Build and make package(s) #
#############################
# 1.  Download the TukBuild file and *.desc, *.required, *.suggests and
#     *.conflicts from the same directory.
# 2.  Source (=read) the TukBuild file.
# 3.  Set PREFIX, LIBDIR, ... and CONFIGURE variables. Their values depend
#     on DISTRO, ARCH and PREFIXTYPE of which only PREFIXTYPE should be set
#     by TukBuild (default is PREFIXTYPE=normal).
# 4.  Download the the files specified in SOURCE and PATCH arrays unless
#     they are found in DISTFILES. MD5 and SHA1 are always checked if they
#     are specified in the TukBuild file.
#     NEW FEATURE: If you need "holes" in NAME, SOURCE, PATCH or their
#     MD5/SHA1 arrays, you can use a hyphen (`-'). The hyphen works also
#     with BUILDSUFFIX, if you want plain numeric build tag.
# 5.  The variable TMP is reset TMP="$TMP/build-$NAME". If TMP was originally
#     not set, it will default to the value of TMPDIR and then fallback
#     to /tmp. It is important to note that after this step TMP will point
#     to e.g. /tmp/build-foo, not what it was set externally (e.g. /tmp).
# 6.  The temporary directory pointer by TMP is created. Unless CLEANUP=0 is
#     specified (equivalent to command line flag -C), the directory will be
#     be erased first. If erasing is fails, tukbuild will return an error.
# 7.  The current directory is changed to TMP. The command specified in
#     BUILD_COMMAND (default is BUILD_COMMAND=build) is run and the actual
#     build process should now start.
# 7.  If an error occurs while building, tukbuild will exit and leave
#     temporary files on the disk. When everything goes well, the contents
#     of directories in the PKG array are used to create package files. This
#     includes a few steps like stripping binaries unless STRIP=0 and
#     compressing info and man pages unless COMPRESS_MAN=0. The packages will
#     be put to the directory pointer by PACKAGES.
# 8.  Unless CLEANUP=0 (command line flag -C) was specified, the temporary
#     directory will be removed.
# 9.  Repeat from the step 1. as long as no errors occur and there are
#     TukBuild files left.

_STANDALONE=0
if [ "$(type -t build)" = "function" ]; then
	# build() is already defined, so we are in standalone mode (the
	# TukBuild file is embedded to the beginning of the tukbuild tool).
	set -- "${_TUKBUILD_TOOL}"
	_STANDALONE=1
elif [ $# = 0 ]; then
	# We got no parameters. Search for TukBuild-files case insensitively:
	shopt -s nocaseglob
	set -- *.TukBuild
	shopt -u nocaseglob
	if [ "$1" = "*.TukBuild" ]; then
		echo '+ ERROR: No *.TukBuild files in the' \
				'current directory.'
		exit 1
	fi
fi

for _TUKBUILD; do ( # Open a subshell

	# All errors stop the build process:
	set -e

	if _is_url "${_TUKBUILD}"; then
		CWD_URL=$(dirname "${_TUKBUILD}")
		if [ ! -f "${_TUKBUILD##*/}" ]; then
			_wget "${_TUKBUILD}" "${_TUKBUILD##*/}"
			echo '+ Checking the URL for .desc, .required,' \
					'.suggests and .conflicts files.'
			for I in $(wget $WGET_FLAGS -O - -q "$CWD_URL/" | sed -n \
's#^.*<\(a href\|A HREF\)="\([a-zA-Z0-9:/_.-]\+/\)*\([a-zA-Z0-9_.-]\+\.\(desc\|required\|conflicts\|suggests\)\)">\3</[aA]>.*$#\3#p')
				do
				rm -f "$I"
				_wget "$CWD_URL/$I" "$I"
			done
		fi
		CWD=.
	else
		CWD=$(cd "$(dirname "${_TUKBUILD}")"; pwd)
	fi
	_TUKBUILD="${_TUKBUILD##*/}"

	# In standalone mode we already have the TukBuild file,
	# so it is not sourced.
	if [ "${_STANDALONE}" = "0" ]; then
		echo "+ Reading TukBuild file: $CWD/${_TUKBUILD}"
		source "$CWD/${_TUKBUILD}"
	fi

	# Name and version:
	NAME[0]=$NAME
	VERSION[0]=$VERSION

	# Set BUILDSUFFIX=- if you want no suffix.
	BUILD=${BUILD:-1}
	BUILDSUFFIX=${BUILDSUFFIX:-"$USER"}
	if ! _is_number "$BUILD"; then
		echo '+ WARNING: Non-numeric BUILD tags are deprecated.'
		sleep 3
	elif [ "$BUILDSUFFIX" != "-" ]; then
		BUILD="$BUILD$BUILDSUFFIX"
	fi
	BUILD=$BUILDPREFIX$BUILD

	# Force PREFIXTYPE to lowercase.
	PREFIXTYPE=$(echo "$PREFIXTYPE" | tr A-Z a-z)

	# Set NAMEPREFIX.
	NAMEPREFIX=
	if [ "$NAME_WITH_PREFIXTYPE" = "1" ]; then
		if [ -z "$PREFIXTYPE" -o "$PREFIXTYPE" = "normal" \
				-o "$PREFIXTYPE" = "x11" ]; then
			NAMEPREFIX="base-"
		else
			NAMEPREFIX="${PREFIXTYPE}-"
		fi
	fi

	# Check if TukBuild file has changed ROOT_REQUIRED:
	if [ "$ROOT_REQUIRED" != "0" -a "$UID" != "0" \
			-a "$DOWNLOAD_ONLY" != "1" ]; then
		echo '+ ERROR: This package cannot be built without' \
				'root priviledges.'
		exit 1
	fi

	# Look for problematic pathnames and filenames.
	if echo "$CWD$TMP$DISTFILES$PACKAGES" | fgrep -qs ' '; then
		# "A little bit" generic message but whatever...
		# feel free to improve.
		echo '+ WARNING: Some paths contain spaces. Build may fail.'
		sleep 3
	fi

	# Statistics:
	if [ "$DOWNLOAD_ONLY" != "1" ]; then
		if [ -z "$NAME" ]; then
			echo '+ ERROR: No package names specified' \
					'in sourced file.'
			exit 1;
		fi
		J=0
		for (( I=0; I < ${#NAME[@]}; I++ )); do
			# Same TukBuild may build e.g. i686 (application)
			# and noarch (docs) packages:
			ARCH[I]=${ARCH[I]:-"$ARCH"}
			[ "${NAME[I]}" = "-" -o "${VERSION[I]}" = "-" ] \
					&& continue
			if [ $J = 0 ]; then
				echo '+ About to create the following' \
						'package(s):'
				J=1
			fi
			echo "+   $NAMEPREFIX${NAME[I]}-${VERSION[I]//-/_}-${ARCH[I]}-$BUILD.$PKGFORMAT"
		done
		if [ $J = 0 ]; then
			echo '+ ERROR: The TukBuild file does not specify' \
					'any packages to be built.'
			exit 1
		fi
		unset J

		# Verify PACKAGER_TAG:
		if [ ${#PACKAGER_TAG} -gt 70 ]; then
			echo '+ ERROR: PACKAGER_TAG is too long ' \
					'(max 70 characters).'
		fi

		# Simple integrity check for *.desc files before downloading
		# source and patch files (nicer to get the error message now):
		# TODO: Verify also *.required, *.conflicts and *.suggests.
		echo '+ Verifying *.desc files:'
		for (( I=0; I < ${#SOURCE[@]}; I++ )); do
			if [ -f "$CWD/${NAME[I]}.desc" ]; then
				echo "+   $CWD/${NAME[I]}.desc"
				# Descriptions are limited to 13 lines and
				# 70 characters per line.
				if [ ! -s "$CWD/${NAME[I]}.desc" ]; then
					echo "+ ERROR: Empty description" \
							"file: ${NAME[I]}.desc"
					exit 1
				fi
				if [[ $(wc -l < "$CWD/${NAME[I]}.desc")\
						-gt 13 ]]; then
					echo "+ ERROR: Too many lines (over" \
						"13) in ${NAME[I]}.desc."
					exit 1
				elif ! sed -n '/^.\{71\}/q1' \
						"$CWD/${NAME[I]}.desc"
					then
					echo "+ ERROR: Too long lines (over" \
						"70 chars) in ${NAME[I]}.desc."
					exit 1
				elif [ -n "$PACKAGER_TAG" ] && [[ $(wc -l < \
						"$CWD/${NAME[I]}.desc") \
						== 13 ]]; then
					echo "+ WARNING: ${NAME[I]}.desc" \
							"is 13 lines." \
							"PACKAGER_TAG will" \
							"not be added."
					sleep 3
				fi
			fi
		done
	fi

	echo '+ Locating source and patch files:'
	# Zenwalk includes build scripts and related files in the packages.
	# The indexes of non-URLs are stored to these variables:
	NON_URL_SOURCES=
	NON_URL_PATCHES=
	# Download missing files and check MD5 and SHA1 sums:
	for (( I=0; I < ${#SOURCE[@]}; I++ )); do
		[ "${SOURCE[I]}" = "-" ] && continue
		if ! _is_url "${SOURCE[I]}"; then
			NON_URL_SOURCES="$NON_URL_SOURCES $I"
		fi
		_download "${SOURCE[I]}" "${SOURCE_MD5[I]}" \
				"${SOURCE_SHA1[I]}"
		SOURCE[I]=$RETURN_VALUE
	done
	for (( I=0; I < ${#PATCH[@]}; I++ )); do
		[ "${PATCH[I]}" = "-" ] && continue
		if ! _is_url "${PATCH[I]}"; then
			NON_URL_PATCHES="$NON_URL_PATCHES $I"
		fi
		_download "${PATCH[I]}" "${PATCH_MD5[I]}" "${PATCH_SHA1[I]}"
		PATCH[I]=$RETURN_VALUE
	done
	[ "$DOWNLOAD_ONLY" = "1" ] && exit 0

	if [ "$(type -t build)" != "function" ]; then
		echo '+ ERROR: build() function is not defined.'
		exit 1
	fi

	# Initialize TMP and create temporary directory
	TMP="$TMP/build-$NAME"
	if [ "$CLEANUP" = 1 ]; then
		echo "+ Creating an empty temporary directory: $TMP"
		rm -rf "$TMP" || exit $?
	elif [ -e "$TMP" -a -d "$TMP" ]; then
		echo "+ Using existing temporary directory: $TMP"
	else
		echo "+ Creating a new temporary directory: $TMP"
	fi
	# "mkdir -m 0700" with GNU coreutils 5.2.1 isn't secure IIRC...
	( umask 0077; mkdir -p "$TMP" ) || exit $?

	# Set the prefixes:
	_prefix

	# Optimization flags:
	_cflags "$OPTIMIZE"

	# Create required PKG-directories:
	for (( I=0; I < ${#NAME[@]}; I++ )); do
		[ "${NAME[I]}" = "-" -o "${VERSION[I]}" = "-" ] && continue
		# Having the version number in package-directory makes it
		# possible to build packs like imagemagick-6.x.x_with_x11
		# and imagemagick-6.x.x_no_x11 with the same script.
		PKG[I]="$TMP/package-${NAME[I]}-${VERSION[I]}"
		mkdir -p "${PKG[I]}/install"
	done

	unset I RETURN_VALUE

	# Building starts always in the temporary directory:
	echo '+ Starting the actual build process.'
	cd "$TMP"
	eval "$BUILD_COMMAND"
	echo '+ The build process completed successfully.'

	# Copy the non-URL files to the package if on Zenwalk:
	if [ "$SCRIPTS_TO_PACKAGE" = "1" ]; then
		K="$PKG/usr/src/$NAME-$VERSION"
		echo "+ Copying build script and related files to $K:"
		mkdir -p "$K"
#		if [ "${_STANDALONE}" = "0" ]; then
#			# Combine the .TukBuild and the tukbuild tool into
#			# a standalone script.
#			echo "+   $CWD/${_TUKBUILD} + ${_TUKBUILD_TOOL}"
#			{
#				printf '#!/bin/bash\n\n'
#				cat "$CWD/${_TUKBUILD}"
#				printf '\n\n### DO NOT EDIT BELOW THIS LINE! ###\n\n'
#				cat "{_TUKBUILD_TOOL}"
#			} > "$K/build-$NAME.sh"
#		else
#			# We are building using a standalone script, so
#			# just copy it to the new package.
#			echo "+   $CWD/${_TUKBUILD}"
#			cat "$CWD/${_TUKBUILD}" > "$K/build-$NAME.sh"
#		fi
# 		chmod 0755 "$K/build-$NAME.sh"
		cat "${_TUKBUILD_TOOL}" > "$K/tukbuild"
		# Yeah, .sh is very wrong suffix for 1) TukBuild files
		# and 2) GNU bash scripts. But they want it this way.
		cat "$CWD/${_TUKBUILD}" > "$K/build-$NAME.sh"

		for (( I=0; I < ${#NAME[@]}; I++ )); do
			for J in desc required conflicts suggests; do
				if [ -f "$CWD/${NAME[I]}.$J" ]; then
					echo "+   ${NAME[I]}.$J"
					cp -a "$CWD/${NAME[I]}.$J" "$K"
				fi
			done
		done
		for I in $NON_URL_SOURCES; do
			echo "+   ${SOURCE[I]##*/}"
			cp -a "${SOURCE[I]}" "$K"
		done
		for I in $NON_URL_PATCHES; do
			echo "+   ${PATCH[I]##*/}"
			cp -a "${PATCH[I]}" "$K"
		done
		_chfix "$K"
	fi

	# No longer need to halt on error:
	set +e

	# Make the package(s):
	for (( I=0; I < ${#NAME[@]}; I++ )); do
		[ "${NAME[I]}" = "-" ] && continue

		K="$NAMEPREFIX${NAME[I]}-${VERSION[I]//-/_}-${ARCH[I]}-$BUILD.$PKGFORMAT"
		_makepkg "$I" "$PACKAGES/$K"

		# Zenwalk uses separate .md5 file for every package.
		# The MD5 sums are verified by netpkg.
		if [ "$DISTRO" = "zenwalk" ]; then
			( cd "$PACKAGES" && md5sum "$K" > "${K%.???}.md5" )
		fi
	done

	_cleanup
	echo "+ ${_TUKBUILD} built successfully."

) # Close the subshell

if [ $? != 0 ]; then
	echo "+ ERROR: Build process returned an error. Build stopped."
	exit 1;
fi

done

if [ "$DOWNLOAD_ONLY" = "1" ]; then
	echo "+ All the requested packages successfully downloaded."
else
	echo "+ All the requested packages successfully built."
fi
exit 0
