#
#	Directory stack support for ksh.
#
#	Author:	Ray Lubinsky, rwl@uvacs.cs.virginia.edu
#	Site:	Computer Science Department, University of Virginia
#
#	This file contains functions and aliases which implement a
#	directory stack for the Korn shell very similar to that built
#	into the C-shell.
#
alias cd='chdir'				# THIS IS NOT OPTIONAL
alias pop='popd'				# optional
alias push='pushd'				# optional
#
#	pushd -- push directory stack
#
#	Usage: pushd [<directory> | +<position>]
#
#	You may either change directories by pushing a new directory or
#	by reordering the directory stack.  The directory on the top of
#	the stack (first token in the $DIRSTACK variable) becomes the
#	current working directory.  Giving no arguments is the same as
#	"pushd +1"; see function roll() defined below.
#
function pushd
{
	if [ $# -gt 1 ] ; then
		echo 'pushd: Too many arguments.'
		return 1
	fi
	integer OK=1 FLIP=0 POS=0
	case $1 in
		'')	FLIP=1 ;;
		+*)	POS=${1#+}
			if [ 0 -eq $POS -o $POS -ne "$POS" ] ; then
				echo 'pushd: Bad directory.'
				return 1
			fi ;;
		*)	typeset +x NEWDIR=$1
	esac
	set -- ${DIRSTACK:=$PWD}
	if [ $FLIP -ne 0 ] ; then
		if [ $# -lt 2 ] ; then
			echo 'pushd: No other directory.'
			return 1
		else
			typeset +x SECOND=$1 FIRST=$2
			shift 2
			set -- $FIRST $SECOND $*
		fi
	elif [ $POS -eq 0 ] ; then
		set -- $NEWDIR $DIRSTACK
	elif [ $POS -ge $# ] ; then
		echo 'pushd: Directory stack not that deep.'
		return 1
	else
		typeset +x STACK=''
		integer i=0
		while [ $i -lt $POS ]
		do
			STACK="$STACK $1"
			shift
			let i=i+1
		done
		set -- $* $STACK
	fi
	'cd' $1 1>/dev/null
	OK=$?
	shift
	if [ $OK -eq 0 ] ; then
		DIRSTACK="$PWD $*"
		dirs
	else
		shift
		DIRSTACK=$*
	fi
	return $OK
}
#
#	popd -- pop directory stack
#
#	Usage: popd [+<position>]
#
#	Pop a directory off the directory stack.  With no arguments this
#	pops the top (current working) directory and changes directory to
#	the new top-of-stack directory.  With the position argument, the
#	directory at the given ordinal position from the top of the stack
#	is removed from $DIRSTACK; this never results in a change of current
#	working directory.
#
function popd
{
	if [ $# -gt 1 ] ; then
		echo 'popd: Too many arguments.'
		return 1
	fi
	integer OK=0 POS=0
	case $1 in
		'')	OK=1 ;;
		+*)	POS=${1#+}
			if [ 0 -lt $POS -a $POS -eq "$POS" ] ; then
				OK=1
			fi
	esac
	if [ $OK -eq 0 ] ; then
		echo 'popd: Bad directory.'
		return 1
	fi
	set -- $DIRSTACK
	if [ $# -le 1 ] ; then
		echo 'popd: Directory stack empty.'
		return 1
	elif [ $POS -eq 0 ] ; then
		shift
	elif [ $POS -ge $# ] ; then
		echo 'popd: Directory stack not that deep.'
		return 1
	else
		typeset +x STACK=''
		integer i=0
		while [ $i -ne $POS ]
		do
			STACK="$STACK $1"
			shift
			let i=i+1
		done
		shift
		set -- $STACK $*
	fi
	'cd' $1 1>/dev/null
	OK=$?
	if [ $OK -eq 0 ] ; then
		DIRSTACK=$*
		dirs
	fi
	return $OK
}
#
#	chdir -- wrapper function for cd which adjusts DIRSTACK
#
#	Usage: chdir [<directory>]
#
#	This function is used as the change-directory function.  To have cd
#	work right, you must alias cd to chdir.  Note that instances of cd
#	in this function are quoted so that you get the real builtin rather
#	than the alias.
#
function chdir
{
	typeset +x DIR
	case $# in
		0)	DIR=$HOME ;;
		1)	DIR=$1 ;;
		2)	DIR=`echo $PWD | /bin/sed "s%$1%$2%"` ;;
#		2)	DIR=`echo $PWD | /bin/sed "s$1$2"` ;;
		*)	echo 'cd: too many arguments' ; return 1
	esac
	if 'cd' $DIR 1>/dev/null ; then
		set -- $DIRSTACK
		DIRSTACK=$PWD
		if [ $# -gt 1 ] ; then
			shift
			DIRSTACK="$DIRSTACK $*"
		fi
		dirs
	else
		return 1
	fi
}
#
#	roll -- roll directory stack
#
#	Usage: roll [<count>]
#
#	I use this function when I want to roll the directory stack rather
#	than using "pushd +<count>" to avoid typing extra characters.
#	With no arguments, the function is equivalent to "pushd +1".
#
function roll
{
	typeset +x ROLL
	case $# in
		0)	ROLL=1 ;;
		1)	case $1 in
				[0-9]*) ROLL=$1 ;;
				*)	echo 'roll: number expected' ; return 1
			esac ;;
		*)	echo 'roll: too many arguments' ; return 1 ;;
	esac
	pushd +$ROLL
}
#
#	dirs -- print directory stack
#
#	Usage: dirs
#
#	Like the C-shell builtin, this prints the directory stack.
#
function dirs
{
	if [ "$HOME" = '/' ] ; then
		echo ${DIRSTACK:=$PWD}
	else
		echo ${DIRSTACK:=$PWD} | /bin/sed "s%$HOME%~%g"
#		echo ${DIRSTACK:=$PWD} | /bin/sed "s$HOME~g"
	fi
}
