# Rod's .bashrc file (Rod Moffitt rod@rod.info)
# $Id: bashrc 27143 2025-06-17 17:21:58Z rmoffitt $

# Copyright (C) Rod Moffitt + others
# 
# 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.

# if not running interactively, don't do anything
[ -z "$PS1" ] && return

# source the system bashrc if one exists
if [ -e "/etc/bash.bashrc" ]; then
   . /etc/bash.bashrc
fi

# automatic setting of $DISPLAY (if not set already)
# this works for linux - your mileage may vary...
function get_xserver
{
   case $TERM in
      xterm )
         XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' )
         XSERVER=${XSERVER%%:*}
      ;;
      aterm | rxvt)
         # find some code that works here...
      ;;
   esac
}

if [ -z ${DISPLAY:=""} ]; then
   get_xserver

   if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) || ${XSERVER} == "unix" ]]; then
      DISPLAY=":0.0"          # display on local host
   else
      DISPLAY=${XSERVER}:0.0  # display on remote host
   fi
fi

export DISPLAY

# some settings
ulimit -S -c 0          # don't want any coredumps
set -o notify
#set -o noclobber       # to prevent direction deleting files
#set -o xtrace          # useful for debuging
#set -o nounset         # useful for debuging

# enable options
shopt -s cdspell
shopt -s checkhash
shopt -s checkwinsize
shopt -s sourcepath
shopt -s no_empty_cmd_completion # bash >= 2.04 only
shopt -s cmdhist
shopt -s histappend histreedit histverify
shopt -s extglob        # necessary for programmable completion

# disable options
shopt -u mailwarn
unset MAILCHECK         # disable shell warning of incoming mail

export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
export HISTIGNORE="&:bg:fg:h"
export HISTSIZE=10000
export HISTTIMEFORMAT="%F %H:%M:%S "
export HOSTFILE=~/.hosts # put a list of remote hosts in ~/.hosts

# color definitions
red='\e[0;31m'
RED='\e[1;31m'
green='\e[0;32m'
GREEN='\e[1;32m'
blue='\e[0;34m'
BLUE='\e[1;34m'
cyan='\e[0;36m'
CYAN='\e[1;36m'
yellow='\e[0;33m'
YELLOW='\e[1;33m'
NC='\e[0m' # no color

function xtitle
{
   echo -en "\033]0;$*\007"
}

# find a file with a pattern in name:
function ff { find . -type f -iname '*'$*'*' -ls ; }

# find a file with one or more patterns in the name:
function fr { for filename; do echo -n " -iname '*$filename*'"; done | xargs find . -type f ; }
function fl { (for filename; do echo -n " -iname '*$filename*'"; done; echo " -ls") | xargs find . -type f ; }

# find a file with pattern $1 in name and execute $2 on it:
function fe { find . -type f -iname '*'$1'*' -exec "${2:-file}" {} \;  ; }

# find pattern in a set of files and highlight them
function fstr
{
   OPTIND=1
   local case=""
   local usage="fstr: find string in files.
   Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
   while getopts :it opt
   do
      case "$opt" in
         i) case="-i " ;;
         *) echo "$usage"; return;;
      esac
   done

   shift $(( $OPTIND - 1 ))

   if [ "$#" -lt 1 ]; then
      echo "$usage"
      return;
   fi

   local SMSO=$(tput smso)
   local RMSO=$(tput rmso)

   find . -type f -name "${2:-*}" -print0 | xargs -0 grep -sn ${case} "$1" 2>&- | \
   sed "s/$1/${SMSO}\0${RMSO}/gI" | less
}

# cut last n lines in file, 10 by default
function cuttail
{
   nlines=${2:-10}
   sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
}

# crops off the end of stdin to the specified size when a +ve argument,
# otherwise crops off the specified size from the start of a stdin for a
# -ve argument, size is in bytes unless a sufix of k/K (kilobytes 1000),
# m/M (megabytes 1000000), g/H (gigabytes 1000000000) is found - Rod
function crop
{
   local len=$1
   local bs=1

   case "$len" in
      *k|*K|"* k"|"* K") bs=1000 ;;
      *m|*M|"* m"|"* M") bs=1000000 ;;
      *g|*G|"* g"|"* G") bs=1000000000 ;;
      *) ;;
   esac

   len=$(echo $len | sed -e "s#[a-zA-Z]*##g")
   
   if [ $len -le 0 ];
   then
      len=$(echo $len | sed -e "s#\-##g")
      dd bs=$bs skip=$len 2> /dev/null
   else
      dd bs=$bs count=$len 2> /dev/null
   fi
}

# crop a file without having to make an intermediate temp file - Rod
function filecrop
{
   local TMPFILE=tmp.$$
   cat "$1" | crop "$2" > $TMPFILE
   mv -f $TMPFILE "$1"
}

# du will bork if presented with a very large number of files via the command
# line, fdu gets around this by using find to gather the list of files, the first
# parameter is the directory (. if omitted), any other parameters are passed to du
function fdu
{
   local where=.
   local opt=

   if [ "$#" -ge 1 ]; then
      where=$1
      shift

      if [ "$#" -ge 1 ]; then
         opt=$*
      fi
   fi

   find $where -type f -exec du $opt \{\} \;
}

# clean up source files by: 1) fromdos'ing 2) removing excess white-space
# 3) converting tabs to 3 space - Rod
function cleansrc
{
  local fromdos=`which fromdos 2> /dev/null`

  if [ -z "$fromdos" ]; then
     echo "can't find fromdos"
  else
     for filename;
     do
        local TMPFILE=tmp.$$
        $fromdos < "$filename" | sed -e "s/\s*$//g;s/\t/   /g" > $TMPFILE
        mv -f $TMPFILE "$filename"
     done
  fi
}

# lowercase and change spaces and extraneous dots to underscores in filenames - Rod
# - put '-num' before the name to optionally remove leading '999_' numbers
# - put '-count' before the name to optionally prefix the files with an increasing index
# - put '-force' before the name to optionally force the rename ('mv -f')
# - put '-link' before the name to optionally create a symbolic link instead
function lowercase
{
   local mv=`which mv 2> /dev/null`

   if [ -z "$mv" ];
   then
      echo "can't find mv"
   else
      local nonum="";
      local count="";
      local force="";

      for filename;
      do
         case "$filename" in
            "-num" ) nonum="yes";;
            "-count" ) count=1;;
            "-force" ) force=1;;
            "-link" ) link=1;;
            * )
               if [ ! -e "$filename" ];
               then
                  echo "lowercase: $filename doesn't exist"
               else
                  local dir=$(dirname "$filename")

                  if [ $dir == "." ];
                  then
                     dir=""
                  else
                     dir="$dir/"
                  fi

                  local nf=$(basename "$filename" | tr A-Z a-z | \
                     tr '[:cntrl:]\\\177-\377,:;()\-\[\]!@#\$%\^\?\*~{}=]' ' ' | \
                     sed -e 's/"//g' | sed -e "s/'//g" | sed -e 's/`//g' | sed -e s#\&#and#g | \
                     sed -e 's/[[:space:]]/_/g;s/_\+/_/g;s/^_//;s/_$//;s/\_\./\./g;s/\.\_/\_/g')

                  local gotdots=$(echo $nf | grep "\.\." -)

                  while [ "$gotdots" != "" ];
                  do
                     nf=$(echo $nf | sed -e 's/\.\./\./g')
                     gotdots=$(echo $nf | grep "\.\." -)
                  done

                  if [ ! -d "$filename" ];
                  then
                     local last=$nf
                     gotdots=$(echo $nf | grep "\." -)

                     while [ "$gotdots" != "" ];
                     do
                        last=$nf
                        nf=$(echo $nf | sed -e 's/\./_/')
                        gotdots=$(echo $nf | grep "\." -)
                     done
                     nf=$last
                  else
                     nf=$(echo $nf | sed -e 's/\./_/g')
                  fi

                  if [ -n "$nonum" ];
                  then
                     nf=$(echo $nf | sed -e 's#^[0-9]*_##g')
                  fi

                  if [ -n "$count" ];
                  then
                     nf=$(printf "%03d_$nf" $count)
                     count=$(($count + 1))
                  fi

                  local newname="${dir}${nf}"

                  if [ "$filename" != "$newname" ];
                  then
                     if [ -n "$link" ];
                     then
                        ln -s -- "$filename" "$newname"
                        echo "lowercase: '$newname' linked to '$filename'"
                     else
                        if [ -z "$force" ];
                        then
                           $mv -i -- "$filename" "$newname"
                        else
                           $mv -f -- "$filename" "$newname"
                        fi
                        echo "lowercase: '$filename' --> '$newname'"
                     fi
                  else
                     if [ -n "$link" ];
                     then
                        echo "lowercase: '$filename' not linked"
                     else
                        echo "lowercase: '$filename' not changed"
                     fi
                  fi
               fi
            ;;
         esac
      done
   fi
}

# rename files with random names with 32 character file names, preserving the
# file extension - Rod
function randrename
{
   local mv=`which mv 2> /dev/null`

   if [ -z "$mv" ];
   then
      echo "can't find mv"
   else
      for filename;
      do
         if [ ! -e "$filename" ];
         then
            echo "randrename: $filename doesn't exist"
         else
            local dir=$(dirname "$filename")

            if [ $dir == "." ];
            then
               dir=""
            else
               dir="$dir/"
            fi

            local nf=$(basename "$filename")
            local last=$nf
            local gotdots=$(echo $nf | grep "\." -)

            while [ "$gotdots" != "" ];
            do
               last=$nf
               nf=$(echo $nf | sed -e 's/\./_/')
               gotdots=$(echo $nf | grep "\." -)
            done

            last=$(echo $last | sed 's/[^\.]*//')

            local randname=$(randpw 32 | tr A-Z a-z)
            local newname="${dir}${randname}${last}"

            if [ "$filename" != "$newname" ];
            then
               $mv -i -- "$filename" "$newname"
               echo "randrename: $filename --> $newname"
            else
               echo "randrename: $filename not changed"
            fi
         fi
      done
   fi
}

# updates the link to a file - Rod
function relink
{
   if [ "$#" -lt 2 ]
   then
      echo "usage: relink <dir> <file> { <file> ... }"
   elif [ ! -d "$1" ]
   then
      echo "directory '$1' doesn't exist"
   else
      local dir=$1

      shift

      for filename;
      do
         local link=$(find $dir -name $filename)

         if [ -n "$link" ]
         then
            ln -sf "$link"
            echo "relink: linking $link"
         else
            echo "relink: failed to find $file"
         fi
      done
   fi
}

# renames a file adding the resolution to the end - Rod
function renameres
{
   local identify=`which identify 2> /dev/null`
   local mv=`which mv 2> /dev/null`

   if [ "$#" -lt 1 ]
   then
      echo "usage: renameres <dir> <file> { <file> ... }"
   elif [ -z "$identify" ];
   then
      echo "can't find identify (apt-get install imagemagick)"
   elif [ -z "$mv" ];
   then
      echo "can't find mv"
   else
      for filename;
      do
         if [ ! -e "$filename" ];
         then
            echo "renameres: $filename doesn't exist"
         else
            local res=$($identify -ping -format "%wx%h" "$filename")

            if [ -z $res ]
            then
               echo failed to determine resolution of "$filename"
            else

               local filebase=${filename%.*}
               local ext=$((${#filename}-${#filebase}))
               ext=${filename: -$ext}
               res=$(echo "$filebase" | sed "s/$/_${res}$ext/")
               $mv -i -- "$filename" "$res"
               echo "renameres: $filename --> $res"
            fi
         fi
      done
   fi
}

# finds a free loop device and uses it - Rod
function flosetup
{
   if [ "$#" -lt 1 ]; then
      echo "missing file"
      return -1
   fi

   local losetup=`which losetup 2> /dev/null`
   local lobase='/dev/loop';
   local loopidx=0
   local lofile=$1

   if [ -z "$losetup" ];
   then
      echo "can't find losetup"
      return -1
   fi

   if [ ! -f "$lofile" ];
   then
      echo "invalid file"
      return -1
   fi

   while true
   do
      local lodev=$lobase/$loopidx;

      if [ ! -b $lodev ];
      then
         echo "failed to find free loop device"
         return -1
      fi

      $losetup $lodev $lofile 2> /dev/null

      if [ $? -eq 0 ];
      then
         echo "$lodev"
         return 0
      fi

      loopidx=$((loopidx+1))
   done
}

# detaches a loop device based on the mount - Rod
function closetup
{
   if [ "$#" -lt 1 ]
   then
      echo "missing mount"
      return -1
   fi

   local losetup=`which losetup 2> /dev/null`
   local lomount=$1

   if [ -z "$losetup" ];
   then
      echo "can't find losetup"
      return -1
   fi

   loopdev=`$losetup -a 2> /dev/null | grep $lomount | sed s/:.*//g`

   if [ -n "$loopdev" ];
   then
      $losetup -d $loopdev 2> /dev/null
   else
      return -1
   fi
}

# find all files under the current directory which grep the specified id3 
# information, example 'id3find Trainspotting *' - Rod
function id3find
{
   local string=$1
   shift
   local tempfile=/tmp/.id3find.$$
   for file in $@
   do
      id3info $file > $tempfile 2> /dev/null
      test=$(grep -i "$string" $tempfile)
      if [ -n "$test" ]; then echo $file; fi
   done
   rm -f $tempfile
}

# swap 2 filenames around
function swap
{
   local TMPFILE=tmp.$$
   mv "$1" $TMPFILE
   mv "$2" "$1"
   mv $TMPFILE "$2"
}

function my_ps { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
function pp { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }

# get current host related info
function ii
{
   echo -e "\n${RED}You are logged on ${YELLOW}$HOSTNAME$NC as ${GREEN}$USER"
   echo -e "\n${RED}Additionnal information:$NC "; uname -a
   echo -e "\n${RED}Users logged on:$NC "; w -h
   echo -e "\n${RED}Current date:$NC "; date
   echo -e "\n${RED}Machine stats:$NC "; uptime
   echo -e "\n${RED}Memory stats:$NC "; free
   echo
}

# repeat n times command
function repeat
{
   local max
   max=$1
   shift
   for id in `seq $max`; do
      eval "$@"
   done
}

# ask for confirmation
function ask
{
   echo -n "$@" '[y/n] '
   read ans

   case "$ans" in
      y*|Y*) return 0 ;;
      *) return 1 ;;
   esac
}

# cool little function to prevent 'rm * .txt' when you meant 'rm *.txt',
# tcsh beats bash in only this feature, now bash has it as well! - Rod
function rmstar
{
   set +f # re-enable globbing
   local oldargs="$@"

   # search for a '*'
   until [ -z "$1" ]; do
      if [ "$1" == "*" ]; then
         ask "Do you really want to delete all files?"

         if [ "$?" -ne 0 ]; then
            return
         fi
      fi
      shift
   done

   # need to use a hard-coded path to rm, can't use which on some systems
   /bin/rm $oldargs
}

# need to temporarily disable globbing to allow re-running of rm with the
# string as-is, the only down side is that if this alias is run in the
# background then set +f won't be run until the command completes - Rod
alias rm="set -f; rmstar"

# clean up a path, removing excess forward slashes - Rod
function cleanpath
{
   echo $1 | sed -e "s#//*#/#g" -e 's#/$##g' -e 's#/:#:#g'
}

# nice routine to manage paths, first argument is the command:
# to either "insert" it at the beginning, "append" it to the end,
# "remove" the entry, all operating with the second argumemt, or
# any other command string to show the current path - Rod
function path
{
   dir=$(cleanpath "$2")

   PATH=$(cleanpath "$PATH" | sed -e "s/^/:/" -e "s/$/:/" \
      -e "s#:$dir:#:#g" -e "s/^://" -e "s/:$//")

   case "$1" in
      i* ) PATH=$2:$PATH ;;
      a* ) PATH=$PATH:$2 ;;
      r* ) ;;
      * )  echo -e ${PATH//:/\\n} ;;
   esac
}

# echo text taken from stdin using the color specified as the argument
# which must be listed under 'color definitions' above - Rod
function color
{
   eval col=\$$1
   echo -ne $col
   cat /dev/stdin
   echo -ne "$NC"
}

# outputs 8-bit data in colon-separated hex format - Rod
function bin2hex
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      $hexdump -ve '1/1 "%02x:"' | sed 's#:$#\n#'
   fi
}

# outputs 16-bit data in colon-separated hex format - Rod
function bin2hex16
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      $hexdump -ve '2/2 "%04x:"' | sed 's#:$#\n#'
   fi
}

# outputs 32-bit data in colon-separated hex format - Rod
function bin2hex32
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      $hexdump -ve '4/4 "%08x:"' | sed 's#:$#\n#'
   fi
}

# outputs data in hex format, optionally limits length to 
# specified number of hex chars - Rod
function bin2nhex
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      local data=$($hexdump -ve '1/1 "%02x"' | sed 's#$#\n#')

      if [ "$#" -eq 1 ]; then
         data=$(echo $data | head -c $1)
      fi

      echo $data
   fi
}

# outputs data in C friendly char array hex format - Rod
function bin2chex
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      bin2hex | sed -e 's#^#const uint8_t myarray\[\] = { 0x#;s#:#, 0x#g;s#$# };#'
   fi
}

# outputs data in C friendly short array hex format - Rod
function bin2chex16
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ]; then
      echo "can't find hexdump"
   else
      bin2hex16 | sed -e 's#^#const uint16_t myarray\[\] = { 0x#;s#:#, 0x#g;s#$# };#'
   fi
}

# outputs data in C friendly int array hex format - Rod
function bin2chex32
{
   local hexdump=`which hexdump 2> /dev/null`

   if [ -z "$hexdump" ];
   then
      echo "can't find hexdump"
   else
      bin2hex32 | sed -e 's#^#const uint32_t myarray\[\] = { 0x#;s#:#, 0x#g;s#$# };#'
   fi
}

# for every file under a directory create a single line with
# an MD5 hash and the file name converted so it can be
# sorted and easily compared no matter what system it is on
function md5dir
{
   local hashdeep=`which hashdeep 2> /dev/null`

   if [ -z "$hashdeep" ]; then
      echo "can't find hashdeep"
   elif [ $# -ne 1 ]; then
      echo "usage: md5dir <dir>"
   else
      $hashdeep -c md5 -lr ${1} | egrep -v "^(%|#)" | sort -df
   fi
}

# uses md5dir to provide a single hash of a directory
function md5dirsum
{
   local hashdeep=`which hashdeep 2> /dev/null`

   if [ -z "$hashdeep" ]; then
      echo "can't find hashdeep"
   elif [ $# -ne 1 ]; then
      echo "usage: md5dirsum <dir>"
   else
      md5dir "${1}" | $hashdeep -c md5 | egrep -v "^(%|#)" | awk -F, '{print $2}'
   fi
}

# get a random number, between 0 and the argument-1 - Rod
function rand
{
   local base64=`which base64 2> /dev/null`

   if [ $# -lt 1 ]; then
      echo "usage: rand <ceiling>"
   elif [ ! -r "/dev/urandom" ] || [ -z "$base64" ]; then
      echo "can't read /dev/urandom and/or find base64"
   elif [ $1 -gt 0 ]; then
      # get some real entropy
      RANDOM=$(head -c 20 /dev/urandom | $base64 \
         | sed -e "s#[^0-9]*##g" | tail -c 5)

      # because of integer rounding larger numbers cause overflow on results
      echo $(($RANDOM/(32768/$1)))
   else
      echo "invalid ceiling value"
   fi
}

# select randomly from a argument - Rod
function randlist
{
   if [ $# -gt 0 ]; then
      local index=$(rand $#)
      shift $index
      echo $1
   fi
}

# outputs a specific amount of random data - Rod
function randdata
{
   if [ $# -lt 1 ]; then
      echo "how much random data?"
   elif [ $1 -gt 0 ]; then
      head -c $1 /dev/urandom
   else
      echo "invalid length"
   fi
}

# removes repeating characters from a string - Rod
function charuniq
{
   local i
   local str=$1
   local len=$(echo -n $str | wc -c)
   for ((i=1; i < $(($len/2+2)); i++)); do
      str=$(echo "$str" | sed 's/\(.\)\1/\1/g')
   done
   echo "$str"
}

# outputs a random password by piping /dev/urandom into base64, since not all
# password based systems allow non-alphanumerics they are filtered out, takes
# a single parameter which is the number of characters - Rod
function randpw
{
   local base64=`which base64 2> /dev/null`

   if [ $# -lt 1 ]; then
      echo "what length?"
   elif [ -z "$base64" ]; then
      echo "can't find base64"
   elif [ $1 -gt 0 ]; then
      local testlen=0
      local outlen=$1
      local pw=""

      while [ $testlen -lt $outlen ];
      do
         local in=$(head -c $((outlen*5/6+1)) /dev/urandom | $base64)
         pw=$(echo "$pw$in" | tr -cd 'A-Za-z0-9')
         pw=$(charuniq "$pw")
         testlen=$(echo -n $pw | wc -c)
      done

      pw=$(echo "$pw" | head -c $outlen)
      echo "$pw"
   else
      echo "invalid length"
   fi
}

# generate a random 16 bit integer, good for selecting random ports - Rod
function randport
{
   val=$(randdata 32 | bin2nhex 4)
   echo $((0x$val))
}

# randomly moves out files to specified directory from current directory
# until specified size is met - Rod
function randpurge
{
   if [ "$#" -lt 2 ]; then
      echo "randpurge: <size> <destdir>"
      return;
   fi

   local mv=`which mv 2> /dev/null`

   if [ -n "$mv" ]; then
      local len=$1
      local destdir=$2
      local bs=1

      case "$len" in
         *k|*K|"* k"|"* K") bs=1000 ;;
         *m|*M|"* m"|"* M") bs=1000000 ;;
         *g|*G|"* g"|"* G") bs=1000000000 ;;
         *) ;;
      esac

      bslen=$(echo $len | sed -e "s#[a-zA-Z]*##g")

      size=$(du --block-size=$bs -s | sed -e "s#\.##g")

      if [ $bslen -le $size ]; then
         files=$(find . | grep -v ^\.$)
         file2mv=$(randlist $files)

         if [ -n "$file2mv" ]; then
            echo "moving $file2mv to $destdir"
            $mv -i "$file2mv" "$destdir"
            randpurge "$len" "$destdir"
         fi
      fi
   fi
}

# run a command for a specified time (value is any time value supported by
# sleep) - Rod
function runfor
{
   if [ "$#" -lt 2 ]; then
      echo "runfor: <time> <cmd>"
      return;
   fi

   local slptme=$1
   shift

   $* &
   local pid=$!

   (sleep $slptme; kill $pid 2>&1 > /dev/null; kill -9 $pid 2>&1 > /dev/null)&
   fg %1
}

# tar up, compress then encrypt files/dirs - Rod
function enctar
{
   if [ "$#" -lt 2 ]; then
      echo "enctar: <tarball.tbz2.gpg> <file0/dir0> { <file1/dir1> ... }"
      return;
   fi

   tarball=$1
   shift
   tar cjf - --numeric-owner $* | gpg -c --cipher-algo AES256 --s2k-digest-algo \
         SHA256 --s2k-mode=3 --s2k-count=65536 -z 0 > $tarball

   if [ $? -eq 0 ]; then
      echo "created $tarball"
   fi
}

# decrypt a file using gpg and pass the resulting stream to tar - Rod
function dectar
{
   if [ "$#" -lt 2 ]; then
      echo "dectar: <taropts> <tarball>"
      return;
   fi

   taropts=$1
   tarball=$2
   gpg -d < $tarball | tar $taropts --numeric-owner -f -

   if [ $? -ne 0 ]; then
      echo "tar failed ($?)"
   fi
}

# email status of last command - Rod
function emailstatus
{
   rc=$?

   local mail=`which mail 2> /dev/null`
   if [ -z "$mail" ]; then
      echo "can't find mail"
   fi

   if [ $# -eq 2 ]; then
      email=$1
      tag=$2
      echo "$tag status: $rc" | mail $email -s "$tag completed with status $rc"
   else
      echo "usage: emailstatus <emailaddr> <tag>"
   fi
}

# lists all processes taking nontrivial amounts of memory,
# displays in percentage and orders the highest users at top
function psmem
{
   ps aux | awk '{print $4"\t"$11}' | \
        egrep -v "^(0.0\w*|%MEM)" | sort -nr
}

# simple math routine using bc
function math
{
   local bc=`which bc 2> /dev/null`

   if [ -z "$bc" ]; then
      echo "can't find bc"
      return -1
   fi

   echo "scale=2 ; $*" | sed -e "s:x:*:g" | sed -e "s:,::g" | $bc
}

# set the shell prompt
function setprompt
{
   _getpwd()
   {
      WHEREAMI=$PWD
   }

   PROMPT_COMMAND=_getpwd

   case $TERM in
      xterm* | rxvt | linux )
         PS1="\[${CYAN}\]\u \h:\[${GREEN}\]\$WHEREAMI\[${NC}\] ";;
      *screen* )
         # for screen we append the window # after the username
         PS1="\[${CYAN}\]\u:$WINDOW \h:\[${GREEN}\]\$WHEREAMI\[${NC}\] ";;
      * )
         PS1="\u \h:\$WHEREAMI ";;
   esac
}

# startup message, looks best on a dark background
function entry
{
   echo -e "\n${CYAN}bash ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY ${RED}$DISPLAY${NC}"
   date
   echo

   local fortune=`which fortune 2> /dev/null`

   if [ -n "$fortune" ]; then
      $fortune -s
   fi
}

# exit message
function _exit
{
   echo -e "${RED}exiting bash${NC}"
}

# show the prompt
setprompt

# startup message - skip on login or will mess scp, etc.
if [ $SHLVL -ne "1" ]; then
   entry
fi

# exit message - same rule applies
if [ $SHLVL -ne "1" ]; then
   trap _exit EXIT
fi

# tailoring 'less'
lesspipepath=`which lesspipe 2> /dev/null`

if [ -n "$lesspipepath" ]; then
   eval `$lesspipepath`
fi

# disable xon/xoff flow control
stty -ixon

# the following is the output from `dircolors -b` on Ubuntu 10.04:
export LS_COLORS='di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:';
# adding in a few entries for some newer extensions:
LS_COLORS="${LS_COLORS}*.xz=01;31:*.txz=01;31:*.lzma=01;31:*.lz=01;31:*.tlz=01;31:";
export LS_COLORS

# useful aliases
alias mkdir='mkdir -p'     # filter existing parent dir errors and create parent dirs as needed
alias pwd='pwd -P'         # make builtin pwd always show physical path

export PAGER=less
export ACK_PAGER_COLOR=less
export LESSCHARSET='latin1'
export LESS="-i -N -z-4 -e -M -X -F -R -P%t?f%f"
export EDITOR='vim'
export LC_TIME=C
alias vless='vim -u /usr/share/vim/vim72/macros/less.vim'
alias h='history'
alias j='jobs -l'
alias ..='cd ..'
alias ls='ls --color=auto'
alias ll='ls -l'
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias man='LANG=C LESS= man'
alias rename='LANG=C rename'

# spelling typos
alias Grep='grep'
alias kk='ll'
alias dc='cd'

# umask for security
umask 022

# display a nice login banner
if [ -t 0 ]; then
   linux_logo=`which linux_logo 2> /dev/null`

   if [ -n "$linux_logo" ];
   then
      myhn=`hostname -f | tr "[a-z]" "[A-Z]"`
      $linux_logo -L 10 -c -t $myhn -F \
         "#O Version #V\nCompiled #C\nCPU: #M #X #T (#B BMIPs)\nRAM: #R\n\n#U\n#L\n\nWelcome to #E\n"
   fi
fi

# source any extra config from ~/.bash_priv
if [ -f ~/.bash_priv ]; then
    . ~/.bash_priv
fi

# source any extra config from ~/.bash_aliases
if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# enable programmable completion features
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
    . /etc/bash_completion
fi

# add ~/bin to path if it exists
if [ -x ~/bin ]; then
   path append ~/bin
fi

# vim: sw=3 ts=3 expandtab
