#!/bin/bash
#
# original script by Jim Pick <jim@jimpick.com>, GPL'd of course
# many changes and enhancement by Craig Sander <cas@taz.net.au>
#
# hacked by cas to use case instead of if/elif/fi
# hacked by cas to add '-ls' option.  also added error checking for
# -L and -ls options.
# hacked by cas to add '-conf' and '-lsconf' options.
# hacked by cas to add '-md5sum' and '-md5check' options.
# hacked by cas to add '-man' option.
# hacked by cas to add '-s' option (requires grep-dctrl).
# hacked by cas to support multiple string/package arguments
# hacked by cas to add simplistic emulation of 'dpkg -l'

DLOCATEDB=/var/lib/dlocate/dlocatedb
DPKGLIST=/var/lib/dlocate/dpkg-list
DPKG_INFO=/var/lib/dpkg/info

if [ -x /usr/bin/locate.findutils ] ; then
    # locate package is installed
    LOCATE='/usr/bin/locate.findutils' 
else
    # slocate or mlocate diverts locate
    LOCATE=$(/usr/sbin/dpkg-divert --truename /usr/bin/locate)
fi

function dlocate_help {
  cat <<__EOF__
Usage: dlocate [option] [string...]

Options:
  (no option) string  list all records that match
  -S          string      list records where files match
  -L          package     list all files in package
  -l          package     almost-emulation of 'dpkg -l'
  -s          package     print package's status
  -ls         package     'ls -ldF' of all files in package
  -du         package     'du -sck' of all files in package
  -conf       package     list conffiles in package
  -lsconf     package     'ls -ldF' of conffiles in package
  -md5sum     package     list package's md5sums (if any)
  -md5check   package     check package's md5sums (if any)
  -man        package     list package's man pages (if any)
  -lsman      package     list full path/filenames of man pages
  -lsbin      package     list full path/filenames of executable files

  --                      stop processing options.  remainder of
                          command-line is filename(s)

  --ignore-case, -i       ignore case when search for filenames or
                          package names.

  -h                      display this help message and exit.
  -V                      display dlocate's version number and exit.

  The -L, -s, and -S commands are roughly analagous to the
  equivalent dpkg commands.
__EOF__
  exit 1
} 

function dlocate_version {
  #VERSION_BANNER=$(grep-dctrl -X -P dlocate -n -s Version -d \
  #  /var/lib/dpkg/status | sed -e '2s/.*/(&)/')
  VERSION_BANNER="0.93"
  echo "dlocate version "$VERSION_BANNER
  exit
}

function dlocate_option_error () {
  echo "dlocate: unknown option '$1'"
  echo
  echo "Use: 'dlocate -- $1' if you want to search for '$1'"
  exit 1
}

IGNORE_CASE=""
LAST_OPT=0

OPTION="DEFAULT"

PKGS=""
for p in $@; do
      case "$p" in 

        ('--')

            if [ $LAST_OPT -eq 0 ] ; then
                LAST_OPT=1
            else
                PKGS="$PKGS $p"
            fi
            ;;

        (''|'-h'|'-H'|'--help')

            if [ $LAST_OPT -eq 0 ] ; then
                dlocate_help
            else
                PKGS="$PKGS $p"
            fi
            ;;

        ('-v'|'-V'|'--version')

            if [ $LAST_OPT -eq 0 ] ; then
                dlocate_version
            else
                PKGS="$PKGS $p"
            fi
            ;;

        ('--ignore-case'|'-i')             

            if [ $LAST_OPT -eq 0 ] ; then
                IGNORE_CASE='-i'
            else
                PKGS="$PKGS $p"
            fi
            ;;

        ('-S'|'-L'|'-l'|'-s'|'-ls'|'-du'|'-conf'|'-lsconf'|'-md5sum'|'-md5check'|'-man'|'-lsman'|'-lsbin') 
         
            if [ $LAST_OPT -eq 0 ] ; then
                OPTION="$1"
            else
                PKGS="$PKGS $p"
            fi
            ;;

        (-*)
            if [ $LAST_OPT -eq 0 ] ; then
                dlocate_option_error $1
            else
                PKGS="$PKGS $p"
            fi
            ;;

        (*)
            PKGS="$PKGS $p"
            ;;
      esac
done

PKGS=$(echo "$PKGS" | sed -e 's/^ //')

PKGS_REGEXP=$(echo "$PKGS" | sed -e 's/ /|/g')
FILES_REGEXP="$PKGS_REGEXP"
[ -z "$PKGS_REGEXP" ] && PKGS_REGEXP='^$'


if [ "$OPTION" = '-l' ] ; then

    [ -z "$COLUMNS" ] &&
      COLUMNS=$(stty -a 2>&- |
      sed -ne '/columns/s/.*columns \([0-9]*\)[^0-9].*/\1/p');

    [ 0"$COLUMNS" -lt 80 ] && COLUMNS=80;

    ((fieldw=(COLUMNS-24)/4));

    # dpkg uses ((fieldd=fieldw*2+16));
    #
    # limiting the output to COLUMNS-2 characters and losing up to
    # additional 3 characters due to the rounding error.

    ((fieldd=COLUMNS-fieldw*2-6));

    fmt_eq=$(echo ==================================================== |
      cut -c-$fieldw)

    HEADER=$(
      printf \
"Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ %-${fieldw}s %-${fieldw}s %s
+++-${fmt_eq}-${fmt_eq}-${fmt_eq}${fmt_eq}==================\\n" \
            Name Version Description)

    BODY=$(
      egrep $IGNORE_CASE -- "$PKGS_REGEXP" "$DPKGLIST" | while read stat name ver descr; do
      printf "%-2s  %-${fieldw}.${fieldw}s %-${fieldw}.${fieldw}s %-${fieldd}.${fieldd}s\\n" \
        "$stat" "$name" "$ver" "$descr" | sed -e 's/ *$//';
      done )

    [ -n "$BODY" ] && echo -e "$HEADER\n$BODY"

elif [ "$OPTION" = '-S' ] ; then

    $LOCATE -d $DLOCATEDB $IGNORE_CASE -- $PKGS | egrep $IGNORE_CASE "^[-a-zA-Z0-9_.+]+:.*($FILES_REGEXP)"
    result=$?

elif [ "$OPTION" = 'DEFAULT' ] ; then

    $LOCATE -d $DLOCATEDB $IGNORE_CASE -- $PKGS
    result=$?

else 
    
    for PKG in $PKGS; do
    
        case "$OPTION" in
        
            '-L')
                if [ -s $DPKG_INFO/$PKG.list ] ; then 
                    cat $DPKG_INFO/$PKG.list
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
                ;;

            '-s')
                    grep-dctrl -X -P $PKG /var/lib/dpkg/status || \
                    echo Package $PKG does not exist. >&2
                ;;

            '-ls')
                if [ -s $DPKG_INFO/$PKG.list ] ; then
                    xargs -r ls -ldF < $DPKG_INFO/$PKG.list
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
                ;;

            '-du')
                if [ -s $DPKG_INFO/$PKG.list ] ; then 
                    du -sck $(cat $DPKG_INFO/$PKG.list | xargs -r ls -1dF | grep -v "@$\|/$" )
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
                ;;

            '-conf')
                if [ -s $DPKG_INFO/$PKG.conffiles ] ; then 
                    cat $DPKG_INFO/$PKG.conffiles
                else
                    echo Package $PKG not installed or has no conffiles. >&2
                fi
                ;;

            '-lsconf')
                if [ -s $DPKG_INFO/$PKG.conffiles ] ; then 
                    ls -ldF $(cat $DPKG_INFO/$PKG.conffiles)
                else
                    echo Package $PKG not installed or has no conffiles. >&2
                fi
                ;;

            '-md5sum')
                if [ -s $DPKG_INFO/$PKG.md5sums ] ; then 
                    cat $DPKG_INFO/$PKG.md5sums
                else
                    echo Package $PKG not installed or has no md5sums. >&2
                fi
                ;;

            '-lsman')
                if [ -s $DPKG_INFO/$PKG.list ] ; then 
                    dlocate -L $PKG | \
					  grep '/man.*/.*[0-9]/'
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
				;;

            '-man')
                if [ -s $DPKG_INFO/$PKG.list ] ; then 
                    dlocate -L $PKG | \
                        sed -n -e 's/\.gz$//' \
                               -e '/\/man.*\/.*[0-9]/s/^.*\/\([^\/]*\)\.\(.*\)/\2 \1/p'
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
                ;;

            '-lsbin')
                if [ -s $DPKG_INFO/$PKG.list ] ; then 
                    dlocate -L $PKG | \
					  xargs -r ls -lLd 2> /dev/null | \
					  grep -v "^[^-]" | \
					  egrep '^-.{2,8}[xs]' | \
					  sed -e 's/.* \//\//' | \
					  xargs -r ls -1
                else
                    echo Package $PKG not installed or $PKG.list is empty. >&2
                fi
				;;

            '-md5check')
                if [ -s $DPKG_INFO/$PKG.md5sums ] ; then 
				    pushd / >/dev/null 2>&1
                    cat $DPKG_INFO/$PKG.md5sums | \
                        md5sum -c -
					popd >/dev/null 2>&1
                else
                    echo Package $PKG not installed or has no md5sums. >&2
                fi
                ;;

        esac
    done
fi


test -n "$result" && exit $result

