[comp.unix.shell] ksh implementation of pushd, popd, and dirs.

gh@bdblues.altair.fr (gilbert harrus) (01/29/91)

Newsgroups: comp.unix.shell
Subject: ksh emulation of dirs, pushd, and popd of csh
Summary: 
Expires: 
Sender: 
Followup-To: 
Distribution: world
Organization: Gip Altair/INRIA, France
Keywords: 

Somebody asked for examples of ksh scripts. I just moved from [t]csh
to ksh, and I wrote this "package" to learn more about ksh.

Save in a file, say dirs.ksh, and type : eval . dirs.ksh
Not extensively tested...

gilbert harrus

<--------------- cut here------------------------------>
# Emulation of dirs, pushd and popd of csh under ksh
# Send comments (and bug fixes!) to gh@bdblues.altair.fr

dirs() {
	stackdir[0]=`pwd`
	typeset -i i=0
	while let i!=ndirs ; do
# use print rather than echo here as -n is bsdish
		print -n "${stackdir[$i]} "
		let i=i+1
	done
	print
	return 0
}

pushd() {
	stackdir[0]=`pwd`
	typeset -i i j k 

	if [ $# -gt 1 ]; then
		echo "pushd: Too many arguments."
		return 1
	fi

	case "$1" in
# 3 digits less than 200 (otherwise interpreted as a directory name)
	+[1-9]|+[1-9][0-9]|+0[1-9]|+0[1-9][0-9]|+1[0-9][0-9])
		let i=$1
		if [ $i -ge $ndirs ] ; then
			echo "pushd: Directory stack not that deep."
			return 1
		fi
# copy  from 0..i-1 to ndirs..ndirs+i-1
		let j=0
		let k=ndirs
		while let j!=i ; do
			stackdir[$k]=${stackdir[$j]}
			let j=j+1
			let k=k+1
			if [ $k -ge 511 ] ; then
				echo "pushd: fatal internal error."
				return 1
			fi
		done
# move from i to ndirs+i-1 to 0..ndirs-1
		let j=i
		let k=0
		while let k!=ndirs ; do
			stackdir[$k]=${stackdir[$j]}
			let j=j+1
			let k=k+1
		done
		cd ${stackdir[0]}
		;;

	*)	cd $1
		if [ $? -ne 0 ]; then
			return 1
		fi
		let i=ndirs
		let ndirs=ndirs+1
		let j=i-1
		while let i!=0 ; do
			stackdir[$i]="${stackdir[$j]}"
			let i=i-1
			let j=j-1
		done
		;;
	esac
	dirs
	return $?
}

popd() {
	typeset -i i

	if [ $# -gt 1 ]; then
		echo "popd: Too many arguments."
		return 1
	fi

# if there is one argument check that it is a +n, with n<ndirs
# set j to position of the entry to be disgarded.
	if [ $# -eq 1 ]; then
	case "$1" in
	+[1-9]|+[1-9][0-9]|+0[1-9]|+0[1-9][0-9]|+1[0-9][0-9])
		let j=$1
		if [ $j -ge $ndirs ]; then
			echo "popd: Directory stack not that deep."
			return 1
		fi
		;;
	*)
		echo "pushd: Bad directory."
		return 1
		;;
	esac
	else
		let j=0
	fi

	let i=ndirs
	if [ $i -eq 1 ] ; then
		echo "popd: Directory stack empty."
		return 1
	fi
	let ndirs=ndirs-1
	let k=j+1
	while let j!=i ; do
		stackdir[$j]="${stackdir[$k]}"
		let j=j+1
		let k=k+1
	done
	cd ${stackdir[0]}
	dirs
	return $?
}
	
stackdir=`pwd`
typeset -i ndirs=1
typeset -f dirs
typeset -f pushd
typeset -f popd

sanders@peyote.cactus.org (Tony Sanders) (02/08/91)

Here are some csh functions I use converted to ksh (which I'm using now).
    # save directory
    function sd { pwd > $HOME/.dir/,$1 ; }
    # restore directory
    function rd { cd `cat $HOME/.dir/,$1` && pwd ; }

Be sure and run "mkdir $HOME/.dir"
Lets you save directories by name and cd back to them with
support for a default directory, which is nice if you run
X-windows and want to sync up all your windows you the same
directory (just run "sd" in one window and "rd" in all the rest).

This one is handy for programmers:
    alias vm='if [ -f makefile ]; then vi makefile; else vi Makefile; fi'
in csh I use:
    alias vm 'vi [Mm]akefile || vi Makefile'

These are handy for mh users:
    function v { vi `mhpath ${*-cur}`; }
    alias fll='folders @.'
    alias flr='folder -recurse'
    alias fls='folders @. -fast'
    alias pwf='mhpath'
    # cf makes folders look like directories:  cf /inbox; cf /news/comp/ai
    function cf { folder `echo "$*" | sed -e "s/^\//+/" -e "s/^[^+]/@&/"`; }

Here is my latest working creation:
function warp
{
    if [ $# = "0" ]; then
        echo "usage: warp warpid [params]"
        return 1
    fi
    # if [ -f "$HOME/.warp/@$warp" ]; then
    #   . "$HOME/.warp/@$warp" "$1"             # unwarp previous warp
    # fi
    warp="$1"; shift
    . "$HOME/.warp/$warp" "$@"
}

It's a front end to the '.' command (source for csh users).
I'm still working out all the details of how I want it to
work and if I should use the unwarp stuff and when.
Here is a sample warp file:
    if [ ! -f /SOMEDIRECTORY/rrn ]; then
	mount -t newsserverstuff
    fi
    . $HOME/.path			# set default path
    PATH=$PATH:/news/rsbin		# append news directory bin
    export PATH

I have other more complicated examples but I can't really post them.
I have two that setup build environments for different things and
automatically mount and unmount (unwarp) stuff when needed.

For now I unwarp by hand "warp @$warp" when I want.
My original idea was that unwarp would be called automatically when
you warp to something else (if it existed) but the I had the
problem of warping to A in two windows and then warping to B
in one of them.  I still wanted to use A in the first window
but it wanted to unmount my directories so I turned it off.
Maybe I need a refcount or something but that's too complex,
I want to keep it simple.

ideas/comments/suggestions welcome:

-- sanders@peyote.cactus.org
First rule of software:  Throw the first one away.
and so on...
For every message of the day, a new improved message will arise to overcome it.
IBM UUCP Path: cs.utexas.edu!ibmchs!auschs!sanders.austin.ibm.com!sanders
I am not an IBM representative and I speak only for myself.