#!/bin/bash

# bash functions and aliases that may or may not be useful
#
# Copyright (C) 2005 - 2010, Jeroen Roovers <jer@xs4all.nl>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA
#


#Config:
toolpath="${toolpath:-/keeps/gentoo/tools}"
utilpath="${toolpath}/utils.sh"
privpath="${toolpath}/private.sh"
export CVS_GENTOO_X86="/newaches/gentoo/cvs/gentoo-x86/"

blue="\033[00;34m"
bold="\033[00;01m"
brown="\033[00;33m"
cyan="\033[00;35m"
green="\033[01;32m"
normal="\033[00;00m"
pink="\033[01;35m"
red="\033[01;31m"
yellow="\033[01;33m"

# Had to store these somewhere

#define NORMAL_WHITE    "\033[00;00m"        /* Normal White    */
#define BRIGHT_WHITE    "\033[01;29m"        /* Bright White    */
#define NORMAL_BLACK    "\033[00;30m"        /* Normal Grey */
#define BRIGHT_BLACK    "\033[01;30m"        /* Bright Grey */
#define NORMAL_RED  "\033[00;31m"        /* Normal Red  */
#define BRIGHT_RED  "\033[01;31m"        /* Bright Red  */
#define NORMAL_GREEN    "\033[00;32m"        /* Normal Green    */
#define BRIGHT_GREEN    "\033[01;32m"        /* Bright Green    */
#define NORMAL_YELLOW   "\033[00;33m"        /* Normal Yellow   */
#define BRIGHT_YELLOW   "\033[01;33m"        /* Bright Yellow   */
#define NORMAL_BLUE "\033[00;34m"        /* Normal Blue */
#define BRIGHT_BLUE "\033[01;34m"        /* Bright Blue */
#define NORMAL_MAGENTA  "\033[00;35m"        /* Normal Magenta  */
#define BRIGHT_MAGENTA  "\033[01;35m"        /* Bright Magenta  */
#define NORMAL_CYAN "\033[00;36m"        /* Normal Cyan */
#define BRIGHT_CYAN "\033[01;36m"        /* Bright Cyan */
#define NORMAL_GREY "\033[00;37m"        /* Normal Grey */
#define BRIGHT_GREY "\033[01;37m"        /* Bright Grey */

greendot="${green}*${normal}"
yellowdot="${yellow}*${normal}"
reddot="${red}*${normal}"

######################################
# Support functions:
######################################

fakepm() {
	local file="${1}"
	local arg


	if [[ -f ${file} ]]; then
		PVR=${file/.ebuild}
		PVR_SPLIT=$( qatom ${PVR} )
		PN=$( echo ${PVR_SPLIT} | awk '{ print $2; }' )
		PV=$( echo ${PVR_SPLIT} | awk '{ print $3; }' )
		P_REV=$( echo ${PVR_SPLIT} | awk '{ print $4; }' )
		P="${PN}-${PV}"
		if [[ ${P_REV} ]]; then
			PF="${PN}-${PV}-${P_REV}"
		else
			PF="${PN}-${PV}"
		fi
		CATEGORY=$( basename $( readlink -f ${PWD}/.. ) )
		FILESDIR="files/"
		WORKDIR="${PORTAGE_TMPDIR}/portage/${CATEGORY}/${P}/work/"

		# inherit isolated functions (has, hasq, hasv and so on)
		[[ -f /usr/lib/portage/bin/isolated-functions.sh ]] && \
			source /usr/lib/portage/bin/isolated-functions.sh

		# faux inherit function
		inherit() {
			for arg in ${*}; do
				source ${CVS_GENTOO_X86}/eclass/${arg}.eclass
			done
		}

		# faux die function/warning
		die() {
			#echo -e " ${reddot} JeR-QA WARNING:"
			echo -e " ${reddot} ${file} called die \"${*}\"" 1>&2
		}

		# source pass 1
		source ${file} 2>/dev/null

		unset inherit
		alias inherit=true

		# source pass 2
		source ${file} 2>/dev/null

		[[ -z "${S}" ]] || S="${WORKDIR}/${P}"
		if [[ -z ${EAPI} ]] || [[ ${EAPI} = 0 ]]; then
			RDEPEND="${RDEPEND:-$DEPEND}"
		fi
		EAPI="${EAPI:-0}"
	fi
	unset inherit
	unset die
}

isdir() {
	# test -d helper function
	local i
	for i in ${*}; do
		test -d "${i}" || return 1
	done
}

isfile() {
	test -f ${1} 2>/dev/null
}

isebuild() {
	isfile ${1} && test "${1##*.}" = "ebuild"
}

iseclass() {
	isfile ${1} && test "${1##*.}" = "eclass"
}

isposint() {
	test "${1}" -ge 0 2>/dev/null || return 1
}

isdirv() {
	# test -d helper function that is verbose
	local i
	for i in ${*}; do
		if ! isdir "${1}"; then
			echo -e " ${greendot} ${1} should be a directory for this function to work"
			return 1
		fi
	done
}

isinstalled() {
	if type -P ${1} &> /dev/null; then
		return 0
	else
		return 1
	fi
}

getportdir() {
	local portdir="${PORTDIR}"
	if test -z ${portdir}; then
		echo "$( source /etc/make.globals
			source /etc/make.conf
			test -n "${PORTDIR}" && echo ${PORTDIR} || echo "/usr/portage"
		)"
	else
		echo ${portdir}
	fi
}

getportdiroverlay() {
	local portdiroverlay="${PORTDIR_OVERLAY}"
	if test -z ${portdiroverlay}; then
		echo "$(source /etc/make.globals
			source /etc/make.conf
			test -z ${PORTDIR_OVERLAY} &&  echo "/usr/local/portage" || echo ${PORTDIR_OVERLAY}
		)"
	else
		echo ${portdiroverlay}
	fi
}

lsmodules() { # [path] - List modules for the current kernel or in [path]
	local modpath
	if [[ -d ${1} ]]; then
		modpath=${1}
	else
		modpath=/lib/modules/$(uname -r)
	fi
	find ${modpath} -type f -name '*.ko' -exec basename {} .ko \; | sort
}

getportlogdir() {
	local portlogdir="${PORT_LOGDIR}"
	if test -z ${portlogdir}; then
		echo "$(source /etc/make.globals
			source /etc/make.conf
			test -z ${PORT_LOGDIR} && echo "/var/log/portage" || echo "${PORT_LOGDIR}"
		)"
	else
		echo ${portlogdir}
	fi
}

getportdirplusoverlay() {
	getportdir
	getportdiroverlay
}

countargs() {
	echo $#
}

######################################
# Functions:
######################################

cflags() { #
	gcc -march=native -E -v - </dev/null 2>&1 | \
		sed -n -e 's:.* -v - ::p' | \
		sed 's:-D_FORTIFY_SOURCE=2::g;s|^[[:space:]]*||g;s|[[:space:]]$||g'
}

srcuricheck() { # [ebuild] - Check if SRC_URI is valid
	local ebuild="${1}"
	local uri sites
	if [[ -f ${ebuild} ]]; then
		uri=$( fakepm ${ebuild}; echo ${SRC_URI} )
	else
		return 1
	fi

	[[ -z ${uri} ]] && return 1

	if [[ "mirror://" = "${uri#mirror://}" ]]; then
		echo -e " ${greendot} we have mirrors"
		sites="${uri/mirror:\/\/}"
		sites="${sites/\/*/}"
	else
		echo -e " ${greendot} we have no mirrors"
		sites="${uri}"
	fi

	echo ${sites}
}

atoms() { # [ebuild...] - print the =cat/pkg-ver-rev for [ebuild] or cwd
	local args="${*}"
	test -z ${*} 2>/dev/null && args="*.ebuild"
	local atom
	local ebuilds

	# Test whether these really are ebuilds or
	# you'll get funky stuff like CAT/metadata.xml
	for atom in ${args}; do
		test -f ${atom/.ebuild}.ebuild && ebuilds="${ebuilds} ${atom}"
	done
	# TODO: allow paths in arguments by cd'ing to
	# the ebuild's directory inside a subshell
	for atom in ${ebuilds}; do
		echo "=$(basename $(readlink -f $(pwd)/..))/${atom%.ebuild}"
	done | sort -V
}

unifieddiffclean() { # [patch] - Remove .orig and prefix --- a/ and +++ b/
	local file
	for file in ${*}; do
		echo -e " ${greendot} Fixing ${file}"
		sed -i "${file}" \
			-e '/^diff /d' \
			-e '/^Only in /d' \
			-e 's|.orig||g' \
			-e 's|^--- |&a/|g' \
			-e 's|^+++ |&b/|g' \
			|| break
	done
}

emergefromgentoox86() { # [atom..] - Set PORTDIR_OVERLAY to cvs and emerge [atom..]
	[[ -z ${1} ]] && return 1
	if ! [[ $UID = 0 ]]; then
		echo -e " ${reddot} You need to be root to emerge stuff."
		return 1
	fi
	echo " * Repository: ${CVS_GENTOO_X86}"
	PORTDIR_OVERLAY=${CVS_GENTOO_X86} \
		emerge --package-moves=n -v --nodeps ${*}
}

:q() { # - Funny when you start entering that on the command line
	echo "Yeah, right. Quit it alright! :)"
}

qased() { # [sed args] - run sed output through diff, comparing with old file
	local arg args file files SED=$(which sed)
	for arg in ${*}; do
		if [[ -f ${arg} ]]; then
			files="${files} ${arg}"
		elif [[ ${arg} = -i ]]; then
			true # We do not want -i in there
		else
			args="${args} ${arg}"
		fi
	done

	if [[ -z ${files} ]]; then
		echo -e " ${reddot} Expected at least one file path in ${*}."
		return 1
	fi

	for file in ${files}; do
		${SED} ${args} ${file} | diff -u - ${file}
		if [[ $? = 0 ]]; then
			echo -e " ${reddot} QA Notice: sed script didn't make a difference in ${file}"
		elif [[ $? = 2 ]]; then
			echo -e " ${reddot} QA Notice: sed failed in ${file}"
		else
			# Do it for real when $? = 1, i.e. there was a difference
			${SED} ${args} -i ${file}
		fi
	done
}

lslibdeps() { # [directory..] - List packages providing deps for [directory..]
	local dir
	local syslibs='(ld-linux-.*.so|libc\.so|libgomp\.so|libcrypt\.so|libpthread\.so|libm\.so|libgcc_s.so|libdl\.so|librt\.so|libstdc\+\+\.so|libutil.so)'
	local lib libs user file
	for dir in ${*}; do
		echo "# Running scanelf -BRF \"%F-JeR-%n\" ${dir}"
		for libs in $( scanelf -BRF "%F-JeR-%n" ${dir} ); do
				user="${libs%%-JeR-*}"
				echo
				echo "# Looking for libs needed by ${user}"
			[[ -n "${libs}" ]] && libs=$(
				echo ${libs##*-JeR-} | sed -e 's|,| |g'
			)
			[[ -n "${libs}" ]] && libs=$(
				for lib in ${libs}; do
					echo $lib | egrep -v "${syslibs}"
				done
			)
			if [[ -n "${libs}" ]]; then 
				echo "# Listing libs needed by ${user}"
				for file in ${libs}; do
					echo -n "${file}: "
					qfile -C -e ${file} | sed 's|(|#|g;s|)||g' || echo "# ${file}"
				done | sort -u
			else
				echo "# No non-system libraries found."
			fi
		done
	done
}

repocommit() { # [message] - Run repoman commit -m [message] after repofull
	# formerly alias repocommit="repoman commit -m"
	if [[ -z "${1}" ]]; then
		echo -e " ${reddot} Please give me a commit reason"
		return 1
	else
		local reason="${1}"
	fi

	echo -e " ${greendot} Running repoman manifest"
	repoman manifest || return 1
	echo -e " ${greendot} Running repoman full"
	repoman full || return 1
	echo -en " ${greendot} Press any key to commit"
	read
	repoman commit -m "${reason}"
}

cgrep() { # - Sets --color=always, useful for piping to less
	grep ${*} --color=always
}

runverbose() { # [ARGS...] - echo, then run [ARGS...]
	echo ${*} && ${*}
}

runwithscreen() { # COMMAND - run command through screen only within a screen session
	# STY should normally be set exclusively by screen
	if test -n "${STY}" && isinstalled screen; then
		screen ${*}
	else
		${*}
	fi
}

headchangelog() { # - Print the head of ./ChangeLog
	test -f ./ChangeLog && head -n $((${LINES} - 1)) ./ChangeLog
}

lesschangelog() { # [cate-gory/package | path] - show ChangeLog at PORTDIR /relative /current path
	# Absolute path from PORTDIR to ChangeLog:
	if test -n "${1}" -a -f $(getportdir)/${1}/ChangeLog; then
		runwithscreen less $(getportdir)/${1}/ChangeLog
	# Relative path from workdir to ChangeLog:
	elif test -f ${1}/ChangeLog; then
		runwithscreen less ${1}/ChangeLog
	# Path from workdir to ChangeLog:
	elif test -f ChangeLog; then
		runwithscreen less ChangeLog
	fi
}

cleanfilenames() { # - Make filenames simpler to handle DANGER DANGER!
	local i
	if isinstalled renamexm; then
		local renamexm_cmd="renamexm -vR ."
		# Handle spaces first:
		${renamexm_cmd} '-s/ /_/g' .

		# Handle brackets:
		for i in '(' ')'; do
			${renamexm_cmd} -s/${i}/_/g .
		done

		# Turn commas into dots:
		${renamexm_cmd} '-s/,/./g' .

		# Deal with '\'' too:
		${renamexm_cmd} -s/\'/./g .

		# Handle ampersands separately:
		${renamexm_cmd} '-s/&/and/g' .
	else
		echo "Please install sys-apps/rename to use this function."
	fi
}

logsort() { # [FILE]... - sort emerge log FILEs according to dates in names
	local file
	local files
	local pattern

	files=$(
		for pattern in ${@}; do
			echo *${pattern}*.log*
		done
	)

	for file in ${files}; do
		test -f ${file} || continue
		local name
		local date
		local ext
		name=${file%.log*}
		local ext=${file/${name}}
		local date=${name##*:}
		echo "${date}#${name}${ext}"
	done | sort -u | sed -e 's|^[[:digit:]]*-[[:digit:]]*#||g'
}

qlogs() { # PKG HOST - Finds all logs for PKG in the portage log directory.
	local delim="	" # That is a tab
	local logfile logfiles
	local host hosts
	local pattern patterns patternargs
	local arg cat #TODO: Use category more wisely instead of appending and ignoring pkgmove
	local portlogdir="$(readlink -f $(getportlogdir)/../)"

	# Arg check
	for arg in ${@}; do
		if test ${arg} = -; then
			hosts="${hosts} ${HOSTNAME}"
		elif test ${arg} = jer; then
			hosts=$(
				cd ${portlogdir};
				for i in *; do echo $i; done | sort -u
			)
		elif isdir ${portlogdir}/${arg}; then
			hosts="${hosts} ${arg}"
		else
			# Adjust =cat/pkg-ver to cat:pkg-ver and strip .ebuild
			pattern="${arg/\//:}"
			pattern="${pattern/=}"
			if [[ ${pattern} = *.ebuild ]]; then
				pattern="$(basename $(readlink -f ..)):${pattern/.ebuild}"
			fi
			patternargs="${patternargs} ${pattern}"
			patterns="${patterns} ${pattern}"
		fi
	done 

	# Strip leading spaces for neatness
	patternargs=${patternargs# }
	hosts=${hosts# }

	# TODO: On the one hand, finding a CATEGORY for each pattern could
	# speed up finding log files, but it could also find nothing in case of
	# a pkgmove.

	# It certainly wouldn't be wise to assume $HOSTNAME if none is provided
	if test $( countargs ${hosts} ) -lt 1 2>/dev/null; then
		echo -e " ${reddot} No valid hostname given. (You can use \`-' instead of \`${HOSTNAME}' if you like, or \`jer' for all hosts.)"
		return 1
	fi

	# Generate a list of matching files, sorted by the embedded timestamp
	# in the filename
	logfiles=$(
		cd ${portlogdir} || return 1
		for host in ${hosts}; do
			for log in $( cd ${host}; logsort ${patterns} ); do
				du --apparent-size -h ${host}/${log};
			done | sed -e "s|^ ||g" -e "s|[[:space:]]|${delim}|g";
		done
	)

	local IFS="${IFS/${delim}}"
	local matches=$( countargs ${logfiles} )
	if test "${matches}" -gt 1; then
		select logfile in ${logfiles}; do
			if test -z ${logfile}; then
				for logfile in ${logfiles}; do
					echo "${portlogdir}/${logfile#[0-9]*${delim}} "
				done
				echo
				return 0
			fi
			du --apparent-size -h "${portlogdir}/${logfile#[0-9]*${delim}}"
			runwithscreen less "${portlogdir}/${logfile#[0-9]*${delim}}"
		done
	elif test "${matches}" -eq 0; then
		echo -e " ${yellowdot} No log files match \"${patternargs}\" for $( echo ${hosts} )"
	else
		logfile="${logfiles#[0-9]*${delim}}"
		du --apparent-size -h "${portlogdir}/${logfile}"
		runwithscreen less "${portlogdir}/${logfile}"
	fi
}

ebuildvar() { # [variable..] [file..] - expand variables in ebuild compatible files
	local arg ebuild ebuilds columns prettyfile variable variables
	for arg in ${*}; do
		if isebuild ${arg} || iseclass ${arg} || isfile ${arg}; then
			ebuilds="${ebuilds} ${arg}"
		else
			variables="${variables} ${arg}"
		fi
	done

	if test -z ${ebuilds} 2>/dev/null; then
		# No need to run isebuild here
		ebuilds="$(echo *.ebuild)"
	fi

	# Set columns to max filename length
	columns="0"
	for ebuild in ${ebuilds}; do
		[[ ${#ebuild} -gt ${columns} ]] && columns=${#ebuild}
	done

	# Sort the ebuilds according to version
	ebuilds=$( for i in ${ebuilds}; do echo ${i}; done | sort -V )

	if test -z ${variables} 2>/dev/null; then
		echo -e " ${reddot} Please provide some variables to extract." 1>&2
		return 1
	fi

	insertspace() {
		local i="$1"
		for (( i = $1; i > 0; i=$(( ${i} - 1 )) )); do echo -n " "; done
	}

	for ebuild in ${ebuilds}; do
		local prettyfile="$( insertspace $(( ${columns} - ${#ebuild} )) )${ebuild} : "
		for variable in ${variables}; do
			(
				fakepm ${ebuild}
				if test -z ${!variable} 2>/dev/null; then
					echo -e "${red}${prettyfile}(${variable} is not set)${normal}"
				else
					echo -e "${variable}=\"${!variable}\"" | \
						sed -u '/^[[:space:]]*$/d ; s|^|'"${prettyfile}"'|g'
				fi
			)
		done
	done
}

worldedit() { # [atom] - edit portage's world file or insert [atom]
	local world=/var/lib/portage/world
	local tmp=/tmp/world.tmp
	local bak=/tmp/world.bak
	local atom
	if test ${1}; then
		cp ${world} ${bak} -v
		for atom in ${*}; do
			echo ${atom} >> ${bak}
		done
		LC_ALL=C sort -u ${bak} > ${tmp}
		diff -u ${world} ${tmp}
		cp ${tmp} ${world} -v
		rm ${tmp} -rv
	else
		runwithscreen ${EDITOR} ${world}
	fi
}

gdbgetbacktrace() { # EXE CORE - Print backtrace from corefile
	local exe=${1}
	local core=$2

	gdb ${exe} \
		--core ${core} \
		--batch \
		--quiet \
		-ex "thread apply all bt full" \
		-ex "quit"
}

archaliases() { # EBUILD [nostable...] - print a list of arch@.g.o aliases based on keywording of [ebuild] except the listed arches
	local arg arch arches aliases targets
	local ebuild ebuilds

	# Get stable arches
	local stable="$( getarchlist | sed -e '/^$/q' )"

	local nostable="amd64-fbsd mips sparc-fbsd x86-fbsd"

	# Sort arguments into ebuilds and keywords
	for arg in ${*}; do
		isebuild "${arg}" && ebuilds="${ebuilds} ${arg}" && continue
		isvalidarch "${arg}" && nostable="${nostable} ${arg}" && continue
		echo -e " ${yellowdot} ${arg} was not recognised."; return 1
	done

	# Ebuilds
	[[ -n ${ebuilds} ]] && eshowkw
	for ebuild in ${ebuilds}; do
		local keywords
		# get arches from KEYWORDS
		keywords=$( fakepm ${ebuild}; echo ${KEYWORDS} )

		# Strip -arch, -* and ~arch
		arches=" ${keywords}"
		arches=${arches/ -\*/ }
		arches=${arches//\~}

		# Strip unstable arches
		for arch in ${arches}; do
			isstablearch ${arch} || nostable="${nostable} ${arch}"
		done

		# start output
		echo
		echo -e "${greendot} ${ebuild}: ${keywords}"
		if [[ -n ${nostable} ]]; then
			echo "(Omitting ${nostable})"
		else
			echo
		fi
		echo "% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %"
		# Strip command line arches
		local nostablearch
		for nostablearch in ${nostable}; do
			arches="${arches//$nostablearch/}"
		done
		
		# print valid arches
		aliases=$(
			for arch in ${arches}; do
				echo -n "${arch}@gentoo.org, "
			done | sed -e 's|, $||'
		)
		echo ${aliases} | fold -s
		echo "Arch teams, please test and mark stable:"
		echo -e "${yellow}$(atoms ${ebuild})${normal}"
		targets=$( echo ${arches} | sed -e 's|  | |g; s|^ ||g; s| $||g' )
		echo "Target KEYWORDS=\"${targets}\""
		echo -e " ${greendot} Arches to go stable: - $(countargs ${aliases}) -"
		echo "% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %"
	done
}

lsfind() { # <PREFIX> [find options] - List files through find but strip PREFIX
	local prefix="${1}"
	shift
	test -z ${prefix} && prefix="."
	prefix="$(readlink -f ${prefix})"
	find ${prefix} ${*} -type f | grep -v "^${prefix}$" | sed -e "s|^${prefix}/|/|g"
}

whosyncs() { # - Checks what local system is syncing or caching metadata.
	if test -n "${PORTAGE_SYNC_QUEUE}" -a -r "${PORTAGE_SYNC_QUEUE}"; then
		local wfile="${PORTAGE_SYNC_QUEUE}"
	else
		local wfile="/world/gentoo/.syncing"
	fi
	local pfile="/var/run/syncportage.pid"
	local ftime="$(date -r ${wfile} 2>/dev/null +%s)"
	local wtime="$(date -r ${pfile} 2>/dev/null +%s)"
	local queue="$(cat ${wfile})"
	test -n "${queue}" && local shost="$( echo "${queue}" | head -n 1 )"
	local lhost="$(hostname)"
	local stime="$(date +%s)"
	test -z ${wtime} && wtime="${stime}"
	local agel="$(( ${stime} - ${wtime} ))"

	# TODO: to reimplement this, add timestamps (like $stime)
	# to wfile in syncportage.sh:
	#  ^astrid 1253210565$
	#  ^henke 1253210789$
	#  ^elmer 1253210897$
	# and extract those here

	#local ager="$(( ${stime} - ${ftime} ))" # meaningless now that pfile always exists

	# Human readable ager and agel:
	#if test ${ager} -gt 60; then
	#	ager="$((${ager} / 60 )) minutes and $((${ager} % 60)) seconds"
	#else
	#	ager="${ager} seconds"
	#fi
	#if test ${agel} -gt 60; then
	#	agel="$((${agel} / 60 )) minutes and $((${agel} % 60)) seconds"
	#else
	#	agel="${agel} seconds"
	#fi

	# Who syncs?
	if test -z "${shost}"; then
		echo "No system is syncing."
	elif test "${lhost}" != "${shost}"; then
		echo -e " ${greendot} ${shost} is syncing."
		if echo ${queue} | grep -q ${HOSTNAME}; then
			echo -e " ${greendot} I (${lhost}) am waiting to sync."
			echo -e " ${greendot} Queue: $(
				echo ${queue} | \
				tr '\n' ' ' | \
				grep --color=always ${HOSTNAME}
			)"
		else
			echo -e " ${greendot} Queue: $(
				echo ${queue} | \
				tr '\n' ' '
			)"
		fi
	else
		echo -e " ${greendot} I (${lhost}) am syncing."
		echo -e " ${greendot} Queue: $(
				echo ${queue} | \
				tr '\n' ' ' | \
				grep --color=always ${HOSTNAME}
			)"
	fi

	# pidfile is present but other host is syncing
	#if test -f ${pfile} && test "${lhost}" != "${shost}" ; then
}

testebuild() { # [ebuild args] - Run ebuild(1) with FEATURES+=test
	FEATURES="${FEATURES} test" ebuild ${*}
}

euses-checkdoubles() { # - check .desc files for duplicates
	local i
	for i in $(euses --global '' | cut -f1 -d' '); do
		if test $(euses --strict --flag $i | wc -l) -gt 2; then
			euses --strict --flag $i
			echo
		fi
	done
}

showlibs() { # [atom] - print libraries that files from [atom] link to
	qlist -eo ${1} | scanelf -f - -n -q -BF '%f:%n'
}

ebuildswithouthppa() {
	local i
	for i in $(cat /keeps/useflagger_1_ebuilds); do
		(
			fakepm ${1}
			echo "${i} ${KEYWORDS}" | grep -v 'hppa' ;
		)
	done | tee -a /keeps/ebuilds_without_hppa
}

quickpkgall() { # - Runs quickpkg on /var/db/pkg/*/*
	quickpkg \
	$(
		cd /var/db/pkg
		for i in */*; do echo $i; done | sed 's|^|=|g'
	)
}

emergeinfo() { # cat/pkg - Runs 'emerge info' and saves it locally
	local outputfile="/keeps/gentoo/bugs/emerge.info-$(hostname)"
	{ date; PORTAGE_NICENESS=0 emerge --info $* 2>&1 ;} | \
		tee ${outputfile}
	echo ${outputfile}
}

piduser() { # uses up pids until it hits a low one
	mycommands piduser
	echo -e " ${yellowdot} Are you sure you want to do this?"
	read || return 1
	local i=0
	local j=1
	while test ${j} -gt ${i} ; do
		i=${j}
		j=$( bash -c 'echo $$' )
	done
	echo "${i} -> ${j}"
}

sandboxes() { # SECONDS - Output all sandbox activity every SECONDS seconds
	local mysleep=${1}
	local psout=""
	local psout1=""
	local myout=""
	test -z ${mysleep} && mysleep=1
	while sleep ${mysleep}; do
		psout1="${psout}"
		psout="$(grep -a sandbox /proc/[0-9]*/cmdline 2>/dev/null | \
			grep -a -o '\[.*\]')"
		if test "${psout1}JeR" = "${psout}JeR" -a -n "${psout}"; then
			myout='.'
		elif test -z ${psout}; then
			myout=''			
		else
			myout="\n${psout}"
		fi
		echo -en "${myout}"
	done
}

emergepids() { # - Return the process IDs of emerges
	local emergepid
	for emergepid in $(pgrep -f python.*emerge); do
		echo -n "${emergepid}: "
		cat /proc/${emergepid}/cmdline | tr \\0 ' ' | grep --color=none -o 'emerge .*'
	done
}

waitemergepid() { # - Wait for a specific emerge process
	local emergepids="$(pgrep -f python.*emerge)"
	test -z "${emergepids}" && return 0

	# Wait for all pids if any command line option is given
	if test $( countargs ${*} ) -ge 1; then
		echo -e " ${greendot} Waiting for all emerge processes..."
		while echo -en "\b${emergepids}"; do
			emergepids=$( pgrep -f python.*emerge )
			test $( countargs ${emergepids} ) -ge 1 || break
			sleep 5
		done
	else

		local emergepid
		for emergepid in ${emergepids}; do
			echo -en "${brown}${emergepid}:${normal} "
			cat /proc/${emergepid}/cmdline | tr \\0 ' ' | cut -b -320 | grep --color=none -o 'emerge .*'
		done
		if test $( countargs ${emergepids} ) -gt 1; then
			select emergepid in ${emergepids}; do
				waitfor ${emergepid} && return 0
			done
		else
			waitfor ${emergepids} && return 0
		fi
	fi
}

epackage() { # PATTERN - return all CAT/PKG that contain PATTERN
	local i
	if test -n ${*}; then
		for i in "$(getportdirplusoverlay)"; do
			cd ${i}
			for j in *-*/* ; do
				echo ${j}
			done | grep ${*}
			cd - >/dev/null
		done | grep ${*} | sort -u
	fi
}

ecategoryname() { # CAT/PKG - return only the category name CAT
	local i
	for i in ${*} $(cat /dev/stdin); do
		echo ${i%/*}
	done
}

epackagename() { # CAT/PKG - return only the package name PKG
	local i
	for i in ${*} $(cat /dev/stdin); do
		echo ${i#*/}
	done
}

stripversion() { # - return only the canonical name CAT/PKG from stdin's CAT/PKG-VER
	local i
	for i in ${*} $(cat /dev/stdin) ; do
		( this=${i%%-r*}
		echo ${this%-[0-9]*}; )
	done
}

mypackages() { # - Returns all installed packages as =CAT/PKG-VER
	(
		local i
		cd /var/db/pkg
		for i in */*; do
			echo $i
		done
	)
}

allpackages() { # - Returns all installed packages
	mypackages | sed -e 's|^|=|g'
}

lsdeps() { # [atom..] - List reverse dependencies of [atom..]
	local atom revdep revdeps
	for atom in ${*}; do
		# Find rev dependencies
		local revdeps=$( qdepends -C -Q "${atom}" )
		for revdep in ${revdeps}; do
			# Try to install every version / revision
			qatom "${revdep}" | awk '{ print "~" $1 "/" $2 "-" $3; }'
		done
	done
}

lsdepends() { # CAT/PKG - Returns deps of installed packages
	local portdir="$(getportdir)"
	if isdir "${portdir}/${1}"
	then
		cd /var/db/pkg
		grep ${1} *-*/*/*DEPEND | cut -f1-2 -d/ | stripversion
		cd - >/dev/null
	else
		echo -e " ${greendot} ${1} is not a cate-gory/package."
	fi
}

jdepends() { # PATTERN - print installed *DEPEND that contain PATTERN
	if test -n "${1}"; then
		local pattern="${1}"
	else
		return 1
	fi

	fgrep --with-filename --color=always \
		"${pattern}" /var/db/pkg/*/*/*DEPEND | \
		sed -e 's|/var/db/pkg/||g;s|/DEPEND||g;s|/RDEPEND||g'
}

isvalidqatom() { # [atom..] - Take a partial atom and return a complete one
	local atom
	# equal="="
	# catpac="/"
	# pacver="-"
	# verrev="-"

# TODO:	for atom in $(</dev/stdin) ${*}; do
# TODO: Integrate curl(1) so we can just dump a URL onto packagekeywords
	for atom in ${*}; do
		# Clean up punctuation in (bugzilla provided) argument
		atom=$( echo ${atom} | sed 's|^=||;s|[,:;]$||g' )

		# Run through qatom
		atom=$( qatom ${atom} )

		# Split into variables
		local category=$( echo ${atom} | cut -d' ' -f1 )
		local package=$( echo ${atom} | cut -d' ' -f2 )
		local version=$( echo ${atom} | cut -d' '  -f3 )
		local revision=$( echo ${atom} | cut -d\  -f4 )

		# Catch qatom saying the argument is invalid
		[[ ${package} = "(null)" ]] && break

		# Catch empty revision
		if [[ ${revision} = "(null)" || -z "${revision}" ]]; then
				revision=""
		else
			if [[ ${version} = "(null)" ]]; then
				# With no version, revision is illegal
				revision=""
			else
				revision="-${revision}"
			fi
		fi

		# Catch empty category
		if [[ ${category} = "(null)" ]]; then
			category=""
		else
			if [[ ${version} = "(null)" ]]; then
				category="${category}/"
				version=""
			else
				category="=${category}/"
				version="-${version}"
			fi
		fi
		echo ${category}${package}${version}${revision}
	done
}

allpackagesdate() { # - Returns all installed packages as <install-date> =CAT/PKG-VER 
	local i
	for i in $(mypackages); do
		echo "$(
			date -r /var/db/pkg/${i}/${i/[A-Za-z0-9]*\//}.ebuild '+%X %x'
		) =${i}"

	done
}

eversion() { # [PATTERN] - match PATTERN to cat/pkg/ver-rev
	local i
	for i in ${*}; do
		mypackages | fgrep -- ${i#=}
		[[ ${?} -eq 0 ]] || echo -e " ${reddot} ${i} was not found" 1>&2
	done | sort -V
}

eversionn() { # [PATTERN] - match PATTERN to cat/pkg
	local i
	for i in $(eversion "${*}"); do
		qatom ${i} | awk '{ print $1 "/" $2 }'
	done
}

eversions() { # [PATTERN] - match PATTERN to =cat/pkg-ver-rev
	eversion "${*}" | sed -e 's|^|=|g'
}

pkgstatus() {
	local pkg=""
	for pkg in ${*}; do
		echo -e " ${greendot} Installed:"
		eversions ${pkg}
		echo -e " ${greendot} Targeted:"
		stablereason ${pkg}
	done
}

allpackagesonthishostftp() { # - print the number of installed packages to file
	local mypackagefile="/keeps/gentoo/bugs/allpackages-$(hostname)"
	allpackages | \
		tee ${mypackagefile} | wc -l
	echo -e " ${greendot} Wrote package list to ${mypackagefile}"
}

allpackagesabstract() { # - print package list without versions
	allpackages | stripversion | sort -u
}

extractpackages() { # - Returns things that look like CAT/PKG-VER from stdin
	grep -o '[[:alnum:]]*-*[[:alnum:]]*\/[[:alnum:]_\\+.-]*'
}

matchebuilds() { # CAT/PKG - returns ebuilds paths matching CAT/PKG
	local i
	if test -z ${1}; then
		echo -e " ${greendot} Need a CAT/PKG to work with here"
	else
		for i in $(getportdirplusoverlay); do
			echo ${i}/${1}/*.ebuild
		done | sed -e 's/ /\n/g' | grep -v '*'
	fi
}

matchebuildskeywords() { # CAT/PKG - Returns keywords per ebuild
	local i
	if test -z ${1}; then
		echo -e " ${greendot} Need a CAT/PKG to work with here"
	else
		local i
		local pv
		local ca
		for i in $(matchebuilds ${1}); do
			pv="${i/.ebuild/}"
			echo -n "${1%/*}/${pv##*/} "
			(
				fakepm $i
				echo "${KEYWORDS}"
			)
		done
	fi
}

matchebuildsdependencies() { # CAT/PKG - Returns {R,P,}DEPEND per ebuild - NOT READY YET
	local i
	if test -z ${1}; then
		echo -e " ${greendot} Need a CAT/PKG to work with here"
	else
		local pv
		local ca
		for i in $(matchebuilds ${1}); do
			pv="${i/.ebuild/}"
			echo "	 ${1%/*}/${pv##*/} "
			(
				fakepm ${i}
				test -n ${DEPEND} && echo "DEPEND: ${DEPEND}"
				test -n ${RDEPEND}  && echo "RDEPEND: ${DEPEND}"
				test -n ${PDEPEND} && echo "PDEPEND: ${DEPEND}"
				test -n ${CDEPEND} && echo "CDEPEND: ${DEPEND}"
			)
		done
	fi
}

allebuilds() { # - Returns all ebuilds in PORTDIR and PORTDIR_OVERLAY 
	local i
	for i in $(getportdirplusoverlay); do
		echo ${i}/*-*/*/*.ebuild
	done | sed -e 's/ /\n/g'
}

stablereason() { # atom - discovers the bug related to a version install
	local pkw="/etc/portage/package.keywords"
	isdirv "${pkw}" || return 1
	local target=""
	for target in ${*}; do
		local result=""
		test -z ${target} && return 1
		local results="$(
			cd ${pkw} && \
				fgrep --color=none "${target}" * | \
				awk '{ print $1; }'
		)"
		if test -n "${results}"; then
			for result in ${results}; do
				if echo ${result} | grep -q '[0-9]*:#'; then
					echo -e "${yellow}${result%%:*} ${pkw}/${result#*:} (masked)${normal}"
				else
					echo "${result#*:} ${pkw}/${result%%:*}"
				fi
			done
		else
			echo -e " ${greendot} Target not found: ${target}"
		fi
	done
}

stabletargets() { # BUGNO - returns the atoms related to a bug number{
	local pkw="/etc/portage/package.keywords"
	isdirv "${pkw}" || return 1
	local targets="${*}"
	local target
	for target in ${targets}; do
		test -z ${target} && return 1 || target="${pkw}/${target}"
		test -f "${target}" && \
			sed \
				-e '/^#/d' \
				-e '/^[ 	]*$/d' \
				-e 's|\*\*||g' \
				"${target}" | awk '{ print $1;}'
	done
}

writepkwentry() { # atom branch file - Write a package.keywords entry using all args
	if test $(countargs ${*}) -lt 3; then
		echo -e " ${reddot} Not enough arguments."
		return 1
	fi
	# Need to be root
#	if ! test ${UID} = 0; then
#		echo -e " ${reddot} You need to be root to do that."
#		return 1
#	fi

	# Decide whether the file exists, if not touch it	
	local message
	if test -f ${3}; then
		message="Appending"
	else
		touch ${3}
		message="Writing  "
	fi

	# Write to file and display status
	if test ${2} = stable; then
		echo -e " ${greendot} ${message} ${1} to ${3} ..."
		echo "${1}" >> "${3}"
	else
		echo -e " ${greendot} ${message} ${1} ** to ${3} ..."
		echo "${1} "'**' >> "${3}"
	fi
}

alias pkwa="pkw JeR-unstable-ReJ"

pkw() { # [atom] [reason] - Add a package.keywords entry for [atom] based on [reason]
	# TODO: multiball 
	local pkwdir="/etc/portage/package.keywords"
	local arg
	local atom
	local atoms
	local reason
	local validreason validatom
	local branch="stable"

	# TODO: Automatically add = to atoms with versions
	# Figure out what arg is what
	for arg in ${*}; do
		if isposint ${arg}; then
			if test ${validreason}x = yesx; then
				continue
			else
				reason="${arg}"
				validreason=yes
			fi
		elif echo ${arg} | grep -q '^[=~].*-.*/.*-*$' -; then
			atoms="${atoms} ${arg}"
			validatom=yes
		elif echo ${arg} | grep -q '^.*-.*/.*$' -; then
			atoms="${atoms} ${arg}"
			validatom=yes
		elif echo ${arg} | grep -q '^[=~]virtual/.*-.*$' -; then
			atoms="${atoms} ${arg}"
			validatom=yes
		elif echo ${arg} | grep -q '^virtual/.*$' -; then
			atoms="${atoms} ${arg}"
			validatom=yes
		elif test ${arg} = JeR-unstable-ReJ; then
			branch=unstable
		fi
	done

	atoms=$(isvalidqatom ${atoms} )

	# We need a valid reason or we will not know what file to open
	if ! test ${validreason}x = yesx; then
		echo -e " ${reddot} No valid reason given"
		return 1
	fi

	# With no valid atom we can still open a file
	if ! test ${validatom}x = yesx; then
		echo -e " ${yellowdot} No valid atom given"
		echo -e " ${greendot} Opening ${pkwdir}/${reason}"
		runwithscreen ${EDITOR} "${pkwdir}/${reason}"
		return 0
	fi
	
	# Call writepkwentry atom branch filename
	for atom in ${atoms}; do
		writepkwentry "${atom}" "${branch}" "${pkwdir}/${reason}"
	done
}

packageuse() { # cate-gory/package <use flag> - Add to package.use
	if test -n "${1}" && test -n "${2}"; then
		echo "\"${1} ${2}\" >> /etc/portage/package.use"
		echo "${1} ${2}" >> /etc/portage/package.use
	else
		runwithscreen ${EDITOR} /etc/portage/package.use
	fi
}

packageunmask() { # [cate-gory]/[package] - Unmask package through package.unmask
	local punm="/etc/portage/package.unmask"
	if [[ -d ${punm} ]]; then
		if isposint ${1}; then
			runwithscreen ${EDITOR} ${punm}/${1}
		else
			runwithscreen ${EDITOR} ${punm}/0
		fi
	else
		runwithscreen ${EDITOR} ${punm}
	fi
}

packagemask() { # cat/pkg - Mask package through package.mask
	if test -n "${1}"; then
		echo "\"${1}\" >> /etc/portage/package.mask"
		echo "${1}" >> /etc/portage/package.mask
	else
		runwithscreen ${EDITOR} /etc/portage/package.mask
	fi
}

emergesetupdate() { # [@SET] - Run world update, but wait for syncportage
	if test -f /var/run/syncportage.pid; then
		echo -e " ${greendot} Waiting for syncportage to finish ..."
		while test -f /var/run/syncportage.pid; do
			sleep 5
		done
		echo -e " ${greendot} syncportage seems to have finished - continuing ..."
	fi
	emerge -vuaDNt ${*}
}

emergevuaDNtsystem() { # Run world update, but wait for syncportage
	emergesetupdate ${*} @system
}

emergevuaDNtworld() { # Run world update, but wait for syncportage
	emergesetupdate ${*} @world
}

alias emergevuaDNt=emergevuaDNtworld

waitforsyncp() { # Wait for syncportage to finish...
	if test -f /var/run/syncportage.pid; then
		echo -e " ${greendot} Waiting for syncportage to finish..."
		while test -f /var/run/syncportage.pid; do
			sleep 5
		done
	fi
}

waitforpid() { # [PID] - Wait for one PID to finish
	while isdir /proc/${1}/; do
		sleep 3
	done
}

waitfor() { # [CMD|PID].. - Wait for any PID or any process that `pgrep -x CMD' returns
	local pids
	local pid
	local arg
	local any

	# TODO:
	if test "${1}x" = anypidx; then
		any=anypid
		shift
	fi

	for arg in ${@}; do
		if test "${1}" -gt 0 2>/dev/null; then
			pids="${pids} ${arg}"
			continue
		else
			pids="${pids# } $(pgrep -x ${arg})"
		fi
	done

	echo -en " ${greendot} Waiting for ${pids} to finish..."

	for pid in ${pids}; do
		waitforpid ${pid} || break
	done
	echo " Done!"
}

waitforany() { # [CMD].. - Wait for any [CMD] to finish, even after the initial one has finished
	# TODO: waitfor anypid ${@}
	while sleep 1; do
		pgrep $1 > /dev/null
	done
}

justchrootedin() {
	env-update &&
		source /etc/profile &&
		cd &&
		export PS1="(chroot)${PS1}"
}

#Aliases:
makealiases() { # Set up emerge aliases depending on machine type
		# Might have used `arch' but it returns only 'ppc' for
		# a Power Macintosh. Extend as necessary...
	case $(uname -m) in
		i586|i686)
			arch="x86"
			alias ls="ls --color=always"
			;;
		parisc)
			arch="hppa"
			alias ls="ls --color=always"
			alias emergeunstablex86="ACCEPT_KEYWORDS=\"~x86 x86\" emerge"
			alias emergex86="ACCEPT_KEYWORDS=\"x86\" emerge"
			;;
		'Power Macintosh')
			arch="ppc"
			subarch="-macos"
			alias emergeppc="ACCEPT_KEYWORDS=\"${arch}\" emerge"
			alias emergeunstableppc="ACCEPT_KEYWORDS=\"~${arch} ${arch}\" emerge"
			alias emergeppcmacos="ACCEPT_KEYWORDS=\"${arch}${subarch}\" emerge"
			alias top="top -L"
			;;
	esac
	alias emergeunstable="ACCEPT_KEYWORDS=\"~${arch}${subarch}\" emerge"
	alias emergetest="FEATURES='userpriv test' emerge"
	#alias emergetest="FEATURES='test' emerge"

	# arch-independent emerge/portage aliases:
	alias repoignorearches="repoman --ignore-arches"
	alias repocommitignarch="repoman --ignore-arches commit -m"
	# '-t raw -Ub -r8000 -c1' is the magic (de|en)coding sequence
	# for playing (ivam2's) raw ISDN voicemail sound files:
	# ulo="-t raw -Ub -r8000 -c1"
	if isinstalled sox; then
		alias ulawplay="play -t raw -Ub -r8000 -c1"
		alias ulawsox="sox -t raw -Ub -r8000 -c1"
	fi
	alias reswap="swapoff -av && swapon -av"
	alias qloplu="qlop -lu"
	if isinstalled turbotail; then
		alias screenemergelog="runwithscreen -t emerge.log turbotail -n 44 --retry -f /var/log/emerge.log"
	else
		alias screenemergelog="runwithscreen -t emerge.log tail --retry -n 44 -f /var/log/emerge.log"
	fi
	alias screenless="runwithscreen less"
	alias screenwatch="runwithscreen watch"
	alias screenman="runwithscreen man"
	alias screenssh="runwithscreen ssh"
	if isinstalled turbotail; then
		alias screentailf="runwithscreen turbotail --retry -n 25 -f"
	else
		alias screentailf="runwithscreen tail --retry -n 25 -F"
	fi
	alias screenvi="runwithscreen ${EDITOR}"
	isinstalled pinfo && alias screenpinfo="runwithscreen pinfo"
	isinstalled lynx && alias screenhttp="runwithscreen lynx"
	test "x${USER}" = "xroot" || alias screensu="runwithscreen su -"

	# TODO: TESTING scarabeus' eshowkw
	eshowkw() { /usr/bin/eshowkw -A top ${*} || jshowkw; }
}

screenwatchdistcc() {
	runwithscreen watch \
		-n .5 \
		DISTCC_DIR=$(source /etc/make.conf; echo ${DISTCC_DIR}) \
		distccmon-text
}

whichkernel() {
	local fs="$(readlink /boot/vmlinu[xz].sta)"
	local fo="$(readlink /boot/vmlinu[xz].old)"
	local fn="$(readlink /boot/vmlinu[xz])"
	echo "Stable : ${fs/vmlinu[xz]-/}"
	echo "Old    : ${fo/vmlinu[xz]-/}"
	echo "Current: $(uname -r)"
	echo "New    : ${fn/vmlinu[xz]-/} (next)"
	if test ${fn} -nt /proc/version; then
		echo -e " ${yellowdot} New is newer than Current"
	fi
}

fetchdistfile() {
	local file
	for file in ${*}; do
		wget "http://distfiles.gentoo.org/distfiles/${file}"
	done
}

repofull() {
	FEATURES=digest repoman full ${*}
}

repowithoutmask() {
	FEATURES=digest repoman --without-mask
}

findlatestebuild() {
	local i
	for i in $(echo *.ebuild); do
		echo "${i}";
	done | sort -V | tail -n 1 2>/dev/null
}

homepage() { # prints the latest ebuild HOMEPAGE
	local latestebuild=$(findlatestebuild)
	echo $(
		. ${latestebuild} &>/dev/null
		echo ${HOMEPAGE}
	)
}

description() { # prints the latest ebuild DESCRIPTION
	local latestebuild=$(findlatestebuild)
	echo $(
		set -f
		. ${latestebuild} &>/dev/null
		echo ${DESCRIPTION}
	)
}

describepkg() { # [atom] - describe a package in gentoo-x86
	local atom
	local atoms=$(
		local atom
		for atom in ${*}; do
			findpkg ${atom}
		done
	)
	if [[ -d ${REPO} ]]; then
		local repo="${REPO}"
	else
		local repo="${CVS_GENTOO_X86}"
	fi

	for atom in ${atoms}; do
		(
			fakepm ${repo}/${atom}/*.ebuild
			local versions=$(
				qatom ${repo}/${atom}/*.ebuild | cut -d' ' -f3,4 | sed 's| |-|g' | sort -V
			) 
			versions=$( for i in ${versions}; do echo -n "${i} : "; done )
			echo -e "${yellow}${atom}${normal}	: ${DESCRIPTION}"
			echo -e "${yellow}${atom}${normal}	: ${HOMEPAGE}"
			echo -e "${yellow}${atom}${normal}	: ${versions% : }"
			echo
		)
	done
}

findpkg() { # [atom?] - list packages/categories in gentoo-x86
	local atom=""
	local atoms=""
	local destination=""
	local dirfound=""
	local target="${1}"
	if [[ -d ${REPO} ]]; then
		local repo="${REPO}"
	else
		local repo="${CVS_GENTOO_X86}"
	fi

	# Cheaply try to append an argument to the repo path first
	# A subdir of the cwd (./dir)?
	if isdir ${PWD}/${target}; then
		atoms=$(readlink -f ${PWD}/${target})
		atoms="${atoms/$repo}"
	# A subdir of repo (cat/pkg)?
	elif isdir ${repo}${target}; then
		atoms=$(readlink -f ${repo}${target})
		atoms="${atoms/$repo}"
	# A subdir of a subdir of repo (*/pkg)?
	else
		found=$(
			echo ${repo}*/${target} | sed -e "s|${repo}||g"
		)
		local i
		for i in ${found}; do
			dirfound="${dirfound}
$( isdir ${repo}/${i} && echo ${i})"
		done
		found="${dirfound}"
		# Go costly with more globbing [*/pkg|*/*pkg*]
		if test -z ${found} 2>/dev/null; then
			found="$(
				echo ${repo}*${target}* ${repo}*/*${target}* | \
					sed \
						-e 's|CVS||g' \
						-e "s|${repo}||g"
			)"
		fi

		# In case the glob found more than one,
		# separate using newlines rather than spaces,
		# so we can sort them in the next step
		for atom in ${found}; do
			isdir ${repo}${atom// } && atoms="${atoms// }
${atom}"
		done
	fi

	echo "${atoms}" | sed '/^$/d' | sort
}

catmetadata() {
	if [[ -f metadata.xml ]]; then
	sed \
		-e 's:<\(herd\|\/herd\|maintainer\|\/maintainer\)>:\x1b[01;35m&\x1b[00;00m:g' \
		-e 's:<\(upstream\|\/upstream\)>:\x1b[01;30m&\x1b[00;00m:g' \
		-e 's:^[[:space:]]*::g;s:[[:space:]]*$::g;/^$/d' \
		metadata.xml
	fi
}

teleportage() { # [gentoo-x86 dir / atom] - enter [.. dir / atom], run cvs up and show related info
	if ! test ${USER} = jer; then
		echo -e " ${reddot} You are not jer."
		return 1
	fi

	local atom=""
	local destination=""
	local found=""
	local repo="${CVS_GENTOO_X86}"

	# Set $destination through various means ##
	# With no argument given, stay in pwd
	if test -z ${1} &>/dev/null; then
		destination="${PWD}"
	# With -, change to the previous directory
	elif test "${1}x" = "-x"; then
		if test -n "${OLDPWD}"; then
			destination="${OLDPWD}"
		else
			echo -e " ${reddot} No previous directory known..."
			return 1
		fi
	# Get candidate atoms through findpkg()
	elif [[ -n "${1}" ]]; then
		echo -e " ${greendot} Looking for ${1} ..." 1>&2
		local atoms=$( findpkg ${1} )

		# Count the atoms
		if test $( countargs ${atoms} ) -gt 1; then
			select atom in ${atoms}; do
				destination="${repo}${atom}"
				break
			done
		elif test -n "${atoms}"; then
			# Remove whitespace
			for atom in ${atoms}; do
				destination="${repo}${atom}"
			done
		else
			echo -e " ${reddot} No suitable target found"
			return 1
		fi
	else
		destination=${PWD}
	fi

	# Local function to cd, update and list various information
	destreached() {
		if test -d ./CVS; then
			# Only run cvs update on subdirectories
			if ! test "${destination}x" = "${repo}x"; then
				echo -e " ${greendot} Running cvs update ..."
				if cvs update -Pd; then
					echo -e " ${greendot} Done!"
				else
					echo -e " ${reddot} CVS UPDATE FAILED ${reddot}"
				fi
			fi
		fi
		local description=$(description)
		local homepage=$(homepage)
		local i

		for i in "${description}" "${homepage}"; do
			test -z ${i} 2>/dev/null || \
				echo -e " ${greendot} ${i} ${greendot}"
		done

		eshowkw
		catmetadata
		jer_qa_checks
	}

	if test -d "${destination}"; then
		if test "${destination}x" = "${PWD}x"; then
			echo -e " ${brown}= ${destination}"
			echo -e "  ${yellow}[  ${destination//$repo}  ]${normal}"
			destreached ${destination}
		elif test "x${1}" = "x-"; then
			echo -e " ${brown}< ${destination}"
			echo -e "  ${yellow}[  ${destination//$repo}  ]${normal}"
			cd "${destination}" || return 1
			destreached ${destination}
		else
			echo -e " ${brown}> ${destination}"
			echo -e "  ${yellow}[  ${destination//$repo}  ]${normal}"
			cd "${destination}" || return 1
			destreached ${destination}
		fi
	fi

	# unset the local function
	unset -f destreached
}

jer_qa_checks() {
	local ebuilds=$(echo *.ebuild)
	# Check for hppa specific patches and other hackery:
	if ! test -z ${ebuilds} 2>/dev/null; then
		grep -H 'use hppa' ${ebuilds}
		#grep -H 'built_with_use' ${ebuild}
		ebuildvar RESTRICT ${ebuilds} | grep RESTRICT.*test
		ebuildvar IUSE ${ebuilds} | grep logrotate
	fi
}

keywordcommit() { # MESSAGE - do a commit with MESSAGE
	local message
	if test -z "${1}"; then
		echo -e " ${greendot} Cannot commit without a message."
		return 1
	else
		local message="${1}"
		eshowkw
		echo -e " ${greendot} Committing with: \"${message}\"" || return 1
		FEATURES=digest repoman full || return 1
		echangelog "${message}" || return 1
		repoman --ignore-arches commit -m "${message}"
	fi 
}

tinderboxfetch() {
	local deptype=$1
	shift
	local i
	for i in $*; do
		curl -sf "http://tinderbox.dev.gentoo.org/misc/${deptype}index/$(
		 	qatom ${i} | awk '{ print $1 "/" $2;}'
		)"
	done
}

tinderboxb() {
	tinderboxfetch d ${*}
}

tinderboxr() {
	tinderboxfetch r ${*}
}

checkmark() { # EBUILD ARCH BRANCH - mark EBUILD as ~ARCH or ARCH
	test -n "${1}" && local ebuild="${1}" || return 1
	test -n "${2}" && local arch="${2}" || return 1
	test -n "${3}" && local branch="${3}" || return 1
	local keyword=""

	if test "${branch}x" = "stablex"; then
		keyword="${arch}"
	elif test "${branch}x" = "unstablex"; then
		keyword="~${arch}"
	else
		echo -e " ${greendot} \"${branch}\" is not a branch." 1>&2
		return 1
	fi
	
	# TODO: local archs="$(sed -e '/^$/q' $(getportdir )/profiles/arch.list )"
	#local i=""
	#for testarch in ${archs}; do
	#	if test "${arch}x" = "${testarch}x"; then
	#		arch=continue || return 1
	#	fi
	#done

	if test -f "${ebuild}"; then
		ekeyword "${keyword}" "${ebuild}" || return 1
	else
		echo -e " ${greendot} \"${ebuild}\" is not a file." 1>&2
		return 1
	fi
}

keywordreason() { # [reason] "[arch].." [branch] - validate, formulate and return a commit reason
	# TODO: Check if arches really changed
	local arg branch="" arches="" reason="" message=""
	for arg in ${*}; do
		if test "${arg}x" = "stablex"; then
			branch="stable"
		elif test "${arg}x" = "unstablex"; then
			branch="unstable"
		elif isvalidarch ${arg}; then
			arches="${arches} ${arg}"
		else
			reason="${arg}"
		fi
	done

	arches=$(
		local i
		for i in ${arches}; do echo ${i}; done | sort | tr '\n' ' '
	)

	if test "${branch}x" = "stablex"; then
		message="Stable for"
		arches="${arches^^}"
		message="${message} ${arches}"
	elif test "${branch}x" = "unstablex"; then
		local i archlist
		for i in ${arches};
			do archlist="${archlist} ~${i}"
		done
		arches="${archlist}"
		message="Marked ${arches}"
	else	
		echo " * ${branch} is not a valid branch." 1>&2
		echo "   Try \"stable\" or \"unstable\"." 1>&2
		return 1
	fi

	if test -z "${reason}" ; then
		echo " * Please provide a bug number or \"too\"" 1>&2
		echo "   or a \"(complete message)\" as first argument." 1>&2
		return 1
	elif test "${reason}" = "too" ;then
		message="${message} too"
	elif test "${reason}" -gt 0 2>/dev/null; then
		message="${message} (bug #${reason/ /})"
	else
		message="${message} (${reason})"
	fi

	echo "${message/  / }."
}

getarchlist() { # print the list of valid arch keywords
	local arches
	local archlistfile="$(getportdir)/profiles/arch.list"
	if test -f ${archlistfile}; then
		 cat ${archlistfile}
	else
		return 1
	fi
}

isvalidarch() {
	local arch
	for arch in $( getarchlist | sed -e '/^#/d' -e '/^$/d' ); do
		if test ${arch} = ${1}; then
			return 0
		else
			continue
		fi
	done
	return 1
}

isstablearch() {
	local arch
	for arch in $(
		getarchlist | sed -e '/^# Prefix keywords$/q; /^#/d; /^$/d'
	); do
		if test ${arch} = ${1}; then
			return 0
		else
			continue
		fi
	done
	return 1
}

dailytargets() { # [days] - show stabilisation targets no older than [days] or a day
	# Define to at least a single day's additions
	local mtime="1"
	isposint "${1}" && mtime="${1}"
	local lastmerge=$(
		find /etc/portage/package.keywords/ -name '[[:alnum:]]*' -mtime "-${mtime}"
	)
	test -z "${lastmerge}" && return 1

	local i
	for i in ${lastmerge}; do
		test ${i} = /etc/portage/package.keywords/0 && continue
		stabletargets ${i/etc\/portage\/package.keywords\/}
	done | sort -u
}

bugshppa() {
	local URL='https://bugs.gentoo.org/buglist.cgi?bug_file_loc=&bug_file_loc_type=allwordssubstr&bug_id=&bug_id_type=anyexact&bug_status=UNCONFIRMED&bug_status=IN_PROGRESS&bug_status=CONFIRMED&chfieldfrom=&chfieldto=Now&chfieldvalue=&email1=hppa&email2=&emailassigned_to1=1&emailassigned_to2=1&emailcc1=1&emailcc2=1&emailtype1=substring&emailtype2=substring&field0-0-0=product&field0-0-1=component&field0-0-2=short_desc&field0-0-3=status_whiteboard&keywords=STABLEREQ%20KEYWORDREQ&keywords_type=anywords&long_desc=&long_desc_type=allwordssubstr&query_format=advanced&remaction=&short_desc=&short_desc_type=allwordssubstr&status_whiteboard=&status_whiteboard_type=allwordssubstr&type0-0-0=substring&type0-0-1=substring&type0-0-2=substring&type0-0-3=substring&value0-0-0=&value0-0-1=&value0-0-2=&value0-0-3=&votes=&ctype=csv'
	wget -q -O - "${URL}" | \
		awk \
		"{
			# Clean up the fucking CSV
			sub( \"^\", \"\\\"\", \$0 )
			sub( \",\", \"\\\",\", \$0 )
			sub( \"\$\", \"\\\"\", \$0 )
			# Now we have CSV, so the field separator is the comma
			FS = \",\\\"\"
			# Shiny up the Summaries
			#  Remove anything between brackets
			sub( \"\\\(.*\\\)\", \"\", \$8 )
			#  Remove anything that either
			#   1) annoys bash
			#   2) could be interpreted as a modifier of an atom
			gsub( \"[><=\\\"\\\(\\\)':]\", \"\", \$8 )
			# Remove the CSV header line
			if( NR == 1) { getline; }
			# Print only the bug number and the Summary
			print \$1 \" \" \$8
			# TODO: print only bug numbers and use 
			# 'https://bugs.gentoo.org/show_bug.cgi?ctype=xml&id=<<<bug number>>>'
			# to get the actual stabilisation targets
		}"
}

keywordebuilds() { # [branch] [reason] [arch].. [ebuild]..
	local arch arches arg branch discarded ebuilds keyword keywords message
	local reason

	for arg in ${*}; do
		if isposint ${arg} || test "${arg}" = "too"; then
			if test -z "${reason}"; then
				reason="${reason} ${arg}" && continue
			else
				echo -e " ${reddot} One reason is enough!"
				return 1
			fi
		elif isebuild ${arg}; then
			ebuilds="${ebuilds} ${arg}" && continue
		elif test "${arg}" = stable; then
			branch="${arg}"
		elif test "${arg}" = unstable; then
			branch="${arg}"
		elif isvalidarch ${arg}; then
			arches="${arches} ${arg}"
		else
			discarded="${discarded} ${arg}"
		fi
	done

	if ! test -z ${discarded} 2>/dev/null; then
		echo -e " ${reddot} I do not understand: ${discarded}"
		return 1
	fi
	
	if test ${branch} = unstable; then
		for keyword in ${arches}; do
			keywords="${keywords} ~${keyword}"
		done
	else
		keywords="${arches}"
	fi
	
	ekeyword ${keywords} ${ebuilds} || return 1

	message=$( keywordreason ${reason} "${arches}" "${branch}" )
	test "${?}" = "0" || return 1

	repoman manifest || return 1
	keywordcommit "${message}" || return 1
}

stabilise() { # [reason] [arch].. [ebuild]..
	local cleanargs="${*/unstable}"
	if test ${#} -lt 3; then
		echo -e " ${reddot} $(mycommands stabilise)"
		return 1
	fi

	cleanargs="${cleanargs/stable}"
	keywordebuilds ${cleanargs} stable
}

unstabilise() { # [reason] [arch].. [ebuild]..
	local cleanargs="${*/unstable}"
	if test ${#} -lt 3; then
		echo -e " ${reddot} $(mycommands unstabilise)"
		return 1
	fi

	cleanargs="${cleanargs/stable}"
	keywordebuilds ${cleanargs} unstable
}

setporttmpdir() { # PATH - Set PORTAGE_TMPDIR to PATH
		if test -z ${1}; then
			echo PORTAGE_TMPDIR=\""${1}"\"
			unset PORTAGE_TMPDIR
		else
			if isdir "${1}"; then
				echo PORTAGE_TMPDIR=\""${1}"\"
				export PORTAGE_TMPDIR="${1}"
			else
				echo " * ${1} is not a directory."
				return 1
			fi
		fi
		shift
		if ! test -z ${1}; then
			echo -e " ${greendot} You probably wanted to execute this: ${*}"
			${*}
		fi
}

setfeatures() { # KEYWORDS - Set FEATURES to include KEYWORDS
		if test -n "${1}"; then
			echo FEATURES=\""${1}"\"
			export FEATURES="${1}"
		else
			echo FEATURES=\""${1}"\"
			unset FEATURES
		fi
}

newkernel() { # your kernel's mtime with /proc/1
	if test /boot/vmlinux -nt /proc/1; then
		echo -e " ${greendot} Your kernel is younger than your uptime:"
	else
		echo -e " ${greendot} Your uptime is younger than your kernel:"
	fi
	for i in /boot/vmlinux /proc/1; do
		echo -n "$i:	"; stat --format="%y" $i
	done
	uptime
}

jerhighlight() { # STRING - highlight STRING in a stream (stdin)
	sed -u -e "s|${1}|\o33[01;33m&\o33[00;00m|g"
}

maintainer-homepages() { # List maintained packages and respective HOMEPAGEs
	local p i
	for i in /newaches/gentoo/maintainer/*/*; do
		p="${i/\/newaches\/gentoo\/maintainer\/}"
		echo -n "${p}"
		grep -h HOMEPAGE ${CVS_GENTOO_X86}/${p}/*.ebuild \
			| tail -n 1 \
			| sed -e 's|HOMEPAGE=| |g' -e 's|"||g'
	done | column -t
}

maintainer-homepages-html() { # List maintainted packages and HOMEPAGEs in HTML format
	 maintainer-homepages | awk '{ print "<a href=" $2 ">" ${1} "</a>" }'
}

maintainer-update() { # Update symlinks in /newaches/gentoo/maintainer
	local p i move from to
	local cvstree="${CVS_GENTOO_X86}"
	local updates="${cvstree}/profiles/updates"
	local mainttree="/newaches/gentoo/maintainer"

	# Sort updates and return only the latest one
	# FIXME: This assumes older files will no longer be touched
	updates=$(
		stat -c '%Y %n' ${updates}/* \
			| grep -v CVS \
			| sort \
			| awk '{ print $2; }'
	)
	test -z "${updates}" && return 1
	echo -e " ${greendot} Running pkgmoves"
	echo "   from ${updates}"
	echo "     in ${mainttree} ..."

	for i in ${mainttree}/*/*; do
		p="${i/\/newaches\/gentoo\/maintainer\/}"
		move=$( grep "move ${p} " ${updates} | tail -n 1 )
		if test -n "${move}"; then
			from=$( echo ${move} | awk '{ print $2; }' )
			to=$( echo ${move} | awk '{ print $3; }' )
			local olddir=${mainttree}/${from/\/*}
			local newdir=${mainttree}/${to/\/*}
			echo -e " ${greendot} $from -> $to"
			isdir ${newdir} || mkdir -v ${newdir}
			(
				cd ${newdir}
				ln -sfv ${cvstree}/${to}
				rm -v ${mainttree}/${from}
			)
		fi
	done
}

operalocales() { # [WORKDIR] - List locales in WORKDIR, an unpacked www-client/opera tarball
	local opera_workdir="."
	local counter
	local locale_dir
	local LINGUAS_DESC="$(getportdir)/profiles/desc/linguas.desc"

	if ! test -f ${LINGUAS_DESC}; then
		echo -e " ${reddot} Could not find linguas.desc"
		return 1
	fi

	ls_locales() {
		find ${1}/* -maxdepth 1 -type d -exec basename {} \; \
			| grep -v '^en$' \
			| sort
	}
	if test -d ${1}/share/opera/; then
		locale_dir="share/opera/locale"
	elif test -d ${1}/share/opera-next/; then
		locale_dir="share/opera-next/locale"
	fi

	if test -d ${1}/${locale_dir}; then
		echo " * Don't forget to check for weird lowercase usage."
		opera_workdir="${1}/${locale_dir}"
		counter=0
		echo -n "O_LINGUAS=\" "

		for locale in $( ls_locales ${opera_workdir} ); do
			counter=$(( ${counter} + 1 ))
			local locale_m=$( grep -iow -m 1 "${locale/-/_} " ${LINGUAS_DESC} )
			if test -z ${locale_m} 2>/dev/null; then
				echo -ne "${red}${locale}${normal} "
			else
				echo -n "${locale_m/_/-}"
			fi
		done

		echo "\""
		echo " * ${counter} locales"
	else
		echo " * Please pass the path to an unpacked Opera tarball as argument -"
		echo " * No locale dir at ${opera_workdir} ."
	fi

	unset ls_locales
}

######################################
# Internal functions:
######################################

mycommands() { # [<command>] - Describes all commands or just <command>
	local sedstrip=
	if test -z ${1}; then
		grep ^[[:alnum:]]*\(\)\ {\ \# ${utilpath} ${privpath} \
			| sed -e 's|^.*:||;s|() { #||' | sort
	else
		grep ^${1}\(\) ${utilpath} ${privpath} \
			| sed -e 's|^.*:||' -e 's|() { #||' \
			|| echo "$Command \`{1}' not found"
	fi
	
}

myaliases() { # [<alias>] - Describes all aliases or just <alias>
	if test -z ${1}; then
		grep -h ^[[:space:]]*alias ${utilpath} ${privpath} | \
		sed 's/^[[:space:]]*alias //'
	else
		grep -h "^[[:space:]]*alias ${1}" ${utilpath} ${privpath} | \
		sed 's/^.*alias //' || echo "$Command \`{1}' not found"
	fi
}

myresources() { # [-v] - Reload all commands in this file (-v for verbose)
	if test "${1}" = "-v"; then
		test -f "${utilpath}" && source ${utilpath} &&
			echo "Sourcing... ${utilpath}"
		test -f "${privpath}" && source ${privpath} && \
			echo "Sourcing... ${privpath}"
	else
		test -f "${utilpath}" && source ${utilpath}
		test -f "${privpath}" && source ${privpath}
	fi
}

makealiases
test -f "${privpath}" && source ${privpath}

export LESSOPEN="|$(which lesspipe.sh) %s"

#Unconfig:
unset toolpath
test -f ${privpath} || unset privpath

