# $Id: ccd.bash,v 1.9 2004/09/15 14:13:48 oliver Exp $
# (c) 2004 Oliver Beckstein
# made available under the GNU Public License, version 2
#
# source this file in bash to make ccd() available, eg as part of
# the interactive part of your ~/.bashrc
#
#     source ccd.bash
#

# ccd_home must be set to a directory that is accessible on all
# machines from which you can login. 

declare -r ccd_home=${HOME} 2>/dev/null
declare -r ccd_lastdir=${ccd_home}/.lastdir 2>/dev/null

function ccd () {
   local dir=$1 register=$2 err=0
   local mode  # push|pop
   local rdir
   # format of .lastdir:
   # <dir register=REGISTER>DIR</dir> (one per line)
   
   case "$1" in
     -h|--help) echo "
usage: ccd [DIR] [STRING]
       ccd STRING
       ccd COMMAND
pushd DIR and remember the directory in ${ccd_lastdir} so that
a second invocation of ccd (without DIR) in another shell
executes the jump into the same directory. If, as a second argument,
a string is given then the directory will be remembered in a  register 
names STRING and further invocations with this register will recall it 
instead of the default.

Alternatively, commands are available.

COMMANDs:
-h,--help          this help
-s,--show          show all remembered dirs [cat ${ccd_lastdir}]
-E,--erase         remove all registers [rm ${ccd_lastdir}]

NOTE: ccd.bash must be sourced.";
                return 0;;
     -s|--show) cat ${ccd_lastdir}|sort; return 0 ;;
     -E|--erase) rm ${ccd_lastdir}; return $? ;;
     -*)        echo "Unknown option."; return 1 ;;
   esac;

   : ${register:="default"}

   if [ $# -eq 2 ]; then
       mode="push";               # do a pushd on a named register
   elif [ $# -eq 1 ]; then        # can be pushd/default or pop/reg
      # if $dir exists as a key in lastlist then pop/reg
      # dir == register !
      # test read
      if [ -r ${ccd_lastdir} ] && ccd.read ${dir} >/dev/null; then
          mode="pop"; register="${dir}"
      else
          mode="push"; 
      fi
   else
      mode="pop"; register="default";
   fi   

   case ${mode} in
       push)   ;;
       pop)    dir=$(ccd.read ${register});;
   esac;
   
   # echo "register='${register}' dir='${dir}'"
   pushd >/dev/null ${dir}; err=$?
   dir=$(pwd)
   # echo "register='${register}' dir='${dir}'"
   ccd.write ${register} ${dir}
   return ${err}
}

function ccd.read () {
 local f=${ccd_lastdir} key=$1 val
 key="$(echo ${key} | sed 's,\([.?*\ ]\),\\\1,g')"
 val=$(sed -n "s,^ *<dir register=${key}> *\(.*\)</dir>.*,\1,p" ${f})
 echo ${val}
 test -n "${val}";
 return $?;
}

function ccd.write () {
 # not race proof
 local f=${ccd_lastdir} key=$1 val=$2 
 local tmp protected_key
 tmp=${f}.$$
 protected_key="$(echo ${key} | sed 's,\([.?*\ ]\),\\\1,g')"
 [ -r ${f} ] && \
       egrep -v "<dir register=${protected_key}>.*</dir>" ${f} > ${tmp}
 echo -en "<dir register=${key}>${val}</dir>\n" >> ${tmp}
 cp ${tmp} ${f} && rm ${tmp}
}
