# -*-shell-script-*-

# This contains utility functions that can be called by package scripts

####
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright 2002,2003 Mike Hearn (mike@theoretic.com)
# Copyright 2002,2003 Hongli Lai (h.lai@chello.nl)
# Copyright 2002,2003 Curtis L Knight (knighcl@fastmail.fm)
#
####


#
# If you're looking for extract() here, it's defined in makeinstaller instead
#

##
# $APKG_BUILD_SKIP_CONFIGURE
#
# When set to 1, prepareBuild() will not run configure. This, in combination with $APKG_BUILD_SKIP_CONFIGURE,
# is useful if you only want to create a package but not recompile all the source code.
# If you're not using prepareBuild, your [BuildPrepare] code should respect this variable.
#
# See also: $APKG_BUILD_SKIP_MAKE

##
# $APKG_BUILD_SKIP_MAKE
#
# When set to 1, prepareBuild() will not run make. This, in combination with $APKG_BUILD_SKIP_CONFIGURE,
# is useful if you only want to create a package but not recompile all the source code.
# If you're not using prepareBuild, your [BuildPrepare] code should respect this variable.
#
# See also: $APKG_BUILD_SKIP_CONFIGURE

##
# $ROOTNAME
#
# This variable contains the root name of the package, as given in the specfile

##
# $SHORTNAME
#
# This variable contains the short name of the package, as given in the specfile

##
# $DISPLAYNAME
#
# This variable contains the display name of the package, as given in the specfile

##
# $SOFTWAREVERSION
#
# The software version of the package, as given in the specfile

##
# $INTERFACEVERSION
#
# The interface version of the package, as given in the specfile

##
# prepareBuild
#
# Configure and compile the source code, and install files to a temporay build root directory.
# That build root directory will be compressed by makeinstaller, which will be the main payload for your package.
# This function can only be used if your project is using the GNU Autoconf/Automake build system.
# See also: $APKG_BUILD_SKIP_CONFIGURE and $APKG_BUILD_SKIP_MAKE.
#
# Example:
# [BuildPrepare]
# prepareBuild
# # Yes, this is all.
function prepareBuild() {
    export build_root=`mkdir "${TMP}/apkg-build-root.$$"; echo "${TMP}/apkg-build-root.$$"`
    export __apkg_errors_file=`echo "${TMP}/apkg-build-errors.$$"`

    if [[ "$APKG_BUILD_SKIP_CONFIGURE" != "1" ]]; then
        outn "$intl_FUNCLIB_CONFIGURING"

        # Set x86 optimizations
        local oCFLAGS="$CFLAGS"
        local oCXXFLAGS="$CXXFLAGS"
        if uname -m | grep -Ei '(i.?86|athlon)' &>/dev/null; then
            export CFLAGS='-O2 -march=i586 -mcpu=i686'
            export CXXFLAGS='-O2 -march=i586 -mcpu=i686'
            local TARGET='--target=i586-pc-linux'
        fi

        if [[ "$APKG_BUILD_VERBOSE" = "1" ]]; then
            touch "$__apkg_errors_file"
            ./configure --prefix=/usr/local --enable-prefixdb "$TARGET" "$@"
        else
            ./configure --prefix=/usr/local --enable-prefixdb "$TARGET" "$@" >/dev/null 2>"$__apkg_errors_file"
        fi
        local exitCode=$?
        CFLAGS="$oCFLAGS"
        CXXFLAGS="$oCXXFLAGS"

        if [[ "$exitCode" = "0" ]]; then
	    if [[ "`cat \"$__apkg_errors_file\"`" != "" ]]; then
	        cyan; out "    $intl_DONE_WITH_WARNINGS";
	        cat "$__apkg_errors_file"; normal;
            fi
        else
            red; echo "   $intl_FAILED"; 
            normal; cat "$__apkg_errors_file";
            exit 1;
        fi
        green; out "    $intl_DONE"; normal;
    fi

    if [[ "$APKG_BUILD_SKIP_MAKE" != "1" ]]; then
        outn "$intl_FUNCLIB_MAKING";

        # reset the errors/warnings file
        echo "" >"$__apkg_errors_file" 

        if [[ "$APKG_BUILD_VERBOSE" = "1" ]]; then
            touch "$__apkg_errors_file"
            make
        else
            make >/dev/null 2>"$__apkg_errors_file"
        fi
        if [[ "$?" = "0" ]]; then
            if [[ "`cat \"$__apkg_errors_file\"`" != "" ]]; then
                cyan; out "    $intl_DONE_WITH_WARNINGS";
                cat "$__apkg_errors_file; normal";
            else
                green; out "    $intl_DONE";
                normal;
            fi
        else
            red; echo "   $intl_FAILED";
            normal; cat "$__apkg_errors_file";
            exit 1;
        fi;
    fi
    
    echo "" >"$__apkg_errors_file";
    outn "$intl_FUNCLIB_INSTALLING" "$build_root";
    if [[ "$APKG_BUILD_VERBOSE" = "1" ]]; then
        touch "$__apkg_errors_file"
        make install prefix="$build_root"
    else
        make install prefix="$build_root" >/dev/null 2>"$__apkg_errors_file"
    fi
    if [[ "$?" = "0" ]]; then
        # eliminate warnings that libtool produces every time
	while w=`grep -n "libtool: install: warning: remember to run" "$__apkg_errors_file" | sed 's/:.*//'`; [[ "$w" != "" ]]; do	    
	    safeSed "$__apkg_errors_file" "${w}d"
	    safeSed "$__apkg_errors_file" "${w}d"
	    # we do it twice to eliminate the line afterwards as well (the spurious warnings come in pairs)
	done
	if [[ "`cat \"$__apkg_errors_file\"`" != "" ]]; then
	    green; out "    $intl_DONE_WITH_WARNINGS";
	    cyan; cat "$__apkg_errors_file"; normal;
	else
	    green; echo "   $intl_DONE"; normal;
	fi
    else
	red; echo "   $intl_FAILED";
	normal; cat "$__apkg_errors_file";
	exit 1;
    fi

    
    rm "$__apkg_errors_file" 2>/dev/null;    
}


##
# unprepareBuild
#
# Cleanup the temporary build root direcory made by prepareBuild().
#
# Example:
# [BuildUnprepare]
# unprepareBuild
function unprepareBuild() {
    # clean up after packaging
    outn "$intl_FUNCLIB_CLEANING"
    rm -rf "$build_root"
    green; out "   $intl_DONE"; normal; 
    unset build_root 
}


##
# scanLDLibPath <LIBRARY>
# LIBRARY: The library to search for (expected as libname.so)
# Outputs: A list of found libraries, seperated by newline.
#
# Scan $LD_LIBRARY_PATH for Library.
#
# Example:
# export LD_LIBRARY_PATH=/home/mike/garnome/lib
# scanLDLibPath libglib.so
# # Outputs matches for example:
# #  /home/mike/garnome/lib/libglib-2.0.so
# #  /home/mike/garnome/lib/libglib-2.0.so.0
# #  /home/mike/garnome/lib/libglib-2.0.so.0.200.0
function scanLDLibPath() {
    oIFS="$IFS"
    IFS=":"
    local paths
    paths=( $LD_LIBRARY_PATH )
    IFS="$oIFS"    
    local finalresult=""
    local result=""
    for (( i=0; i<${#paths[*]}; i++ )); do
	if [[ "${paths[$i]}" != "" ]]; then
	    result=`ls -1 "${paths[$i]}/${1}"* 2> /dev/null`
	    finalresult=`echo -e "$finalresult\n$result"`
	fi
    done
    echo "$finalresult"  | grep "\(.\)" | sort | uniq
}


# ------------------------------------------------------------

##
# testForLib [-v] LibraryName
# -v: Verbose mode. Print each version number out on stdout.
# LibraryName: The library to check for.
# Outputs: If -v is specified, a list of found library version numbers.
# Returns: 0 = passed, 1 = library not present.
#
# Check for the existance of a library.
function testForLib() {
    pushOptE; set +e;
    if [[ "$1" == "-v" ]]; then
      local verbose="true";
      shift;
    fi

    local lib="$1"
    local cacheresult=`/sbin/ldconfig -p | grep "${lib}\(\.[[:digit:]\.]*\)\?$" | awk 'BEGIN {FS=" => "} { print $2 }' | (while read; do test -f "$REPLY" && echo "$REPLY"; done)`
    trace cacheresult=$cacheresult
    local libpathresult=`scanLDLibPath "${lib}"`
    trace libpathresult=$libpathresult
    local liblist=`echo -e "$libpathresult\n$cacheresult" | grep "\(.\)" | sort | uniq`
    local result="";
    if [[ "$liblist" == "" ]]; then warn "$1 not found"; popOptE; return 1; fi; # not found in cache
    if [[ "$verbose" != "true" ]]; then popOptE; return 0; fi

    # we want to loop over the results until we find a library that matches the required version
    local oIFS="$IFS"
    IFS=$'\n'
    for l in $liblist; do
        local location=`dirname "$l"`
        local lib_resolved=`resolveLink "$l"`
	trace lib_resolved=$lib_resolved
        if [[ "$verbose" == "true" ]]; then
            result=`echo $lib_resolved | sed 's/^.*\.so.//'; echo "$result"`
        fi	
    done
    IFS="$oIFS"

    if [[ "$result" != "" ]]; then echo `echo "$result" | sort | uniq`; fi
    popOptE;
    return 0;
}


# -------------------------------------------------------------

# called when the install script is done
function _installScriptFinished() {
    createDBEntry "$ROOTNAME";
    terminateFE;
    exit 0;
}

function decompressPayload() {
    echo -n "Please wait: extracting files... "
    file_total=`cat "$payload_dir/payload_file_total"`

    echoProgressBar() {
	echo -n "[";
	for ((i=0; i < 20; i++)) do
	    p=$[ $i * 5 ];
	    if (( $p < $1 )); then
		echo -n "#";
	    else
		echo -n " ";
	    fi
	done
	echo -n "]"
	printf " %3.f%%" $1
    }


    progressbar_inc() { echo -n .; }
    if whereis tput >/dev/null; then
	tput civis;
	progressbar_inc() {
	    (( file_count++ ));
	    (( progress = file_count*100 / file_total ));
	    echo -n "`echoProgressBar $progress`"; 
	    tput cub 27;
	}
    fi;
    pushd $payload_dir >/dev/null # we have to change directories here to work around an obscure misfeature of tar or bzip (one of them doesn't like the format of our root names and tries to do DNS lookups and stuff)
    tar -x --bzip2 -vf "payload.tar.bz2"  |  ( while read a; do progressbar_inc; done; echo; )
    popd >/dev/null
    tput cnorm 2>/dev/null
}


# -------------------------------------------------------------


##
# mkdirs <DIRS..>
# DIRS: The directory/directories to create.
#
# Create directories and records it in the install logs. Directories
# created with this function will be automatically removed at uninstall
# by reverseLog() (only if they're empty of course).

# This could probably be cleaner.
function mkdirs() {
    pushOptE; set +e;
    trace called with: $@
    o=`_mkdirs $1`
    if [[ "$?" == "0" ]]; then
	echo "$o" | while read; do
	    echo "removeDir `escapeFilename \"$REPLY\"`" >> "$apkg_logfile"
	    echo "Dir $REPLY" >> "$apkg_filelist"
	done
	unset o
	popOptE
	trace done
	return 0
    else 
	warn $o
	local t=`out "$intl_MKDIRS_ERROR" "$o"`
	outputFail "$t"
	popOptE
	return 1
    fi
}


# -------------------------------------------------------------

# apkg-log contains list of things we have created (files and directories)
#   files [...] destination
# output is for example  red 
#      mkdir /one
#      mkdir /one/two
#      cp /one/two/three
#      cp /one/two/four
#      mkdir /one/two/five
#

##
# copyFiles <SOURCES> <DESTINATION DIRECTORY>
# SOURCES: One or more files to copy.
# DESTINATION DIRECTORY: The directory to copy the source files to.
#
# Copy one or more files to DESTINATION DIRECTORY. These files are logged
# in the uninstall log and will be automatically removed at uninstall.
#
# Example:
# copyFiles hello.txt world.txt "$prefix/doc"
function copyFiles() {
    pushOptE; set +e;
    oIFS="$IFS"
    IFS=$'\n'

    # copy everything but last argument to an array
    declare -a args
    args=("$@")
    count=${#args[@]}
    (( count-- ))
    i=0
    declare -a files
    while [[ $i -lt count ]]; do
        files[$i]="${args[$i]}"
        (( i++ ))
    done

    location="${args[i]}"
    outputStatus $( out "$intl_INSTALLING_FILES" "$location" )
    mkdirs "$location"

    if ! cp_output=$( LANG= cp -fvdpR --backup=nil --suffix=.apkgbak -- "${files[@]}" "$location" ); then
	# FIXME: improve error reporting here
	popOptE;
	return 1;
    fi
    copied_array=( `echo "$cp_output" | awk 'BEGIN { FS="->" } { print $2 }' | sed 's|^ \`||' | tr -d "\'"` )
    
    element_count=${#copied_array[@]}
    trace copied $element_count files
    index=0
    while [ "$index" -lt "$element_count" ]; do
        local element=`echo "${copied_array[$index]}" | sed 's/ (backup: \`.*)$//'`
        if echo "${copied_array[$index]}" | grep ' (backup: `' >/dev/null; then
            local backup=`echo "${copied_array[$index]}" | sed 's/^.* (backup: \`//; s/)$//'`
        fi

	if [[ ! -d "$element" ]]; then
	    echo "rm `escapeFilename \"$element\"` 2>&-" >> "$apkg_logfile"
            if [[ "$backup" != "" ]]; then
                # Restore backup
                echo "mv `escapeFilename \"$backup\"` `escapeFilename \"$element\"`" >> "$apkg_logfile"
            fi
	    echo "File $element" >> "$apkg_filelist"
	else
	    echo "removeDir `escapeFilename \"$element\"`" >> "$apkg_logfile"
	    echo "Dir $element" >> "$apkg_filelist"
	fi
	let "index = $index + 1"
    done

    IFS="$oIFS"
    popOptE;
}


##
# updateEnv [--append] <VARIABLE> <PATH> 
# VARIABLE: The environment variable to set.
# PATH: The path to add to it.
# --append: Append the value to the variable instead of prepending it.
#
# Prepends a path to an environment variable and add a command in the logfile to
# remove it if needed at uninstall. The modifications to the environment
# variables will be saved in various shell startup scripts.
function updateEnv() {
    pushOptE; set +e;
    if [[ "$1" == "--append" ]]; then append="$1"; shift; fi;
    local var="$1"
    local dest="$2"

    if [[ $append = "--append" ]]; then
        cmd="export $var=\"\$$var:$dest\""
    else
        cmd="export $var=\"$dest:\$$var\""
    fi

    if [[ `id -u` != "0" ]]; then
	files=("$HOME/.bashrc")
    else
	files=("/etc/profile")
    fi

    for file in "${files[@]}"; do
        touch "$file"
        removeLine "$file" "$cmd"
        echo "$cmd" >> "$file"
        echo "if dirIsEmpty \"$dest\"; then removeLine \"$file\" '$cmd'; fi" >> "$apkg_logfile"
    done

    local varCommand=`echo "\$var=\"\\$$var:$dest\""`
    eval "$varCommand"
    popOptE;
}


##
# installExe <FILES>
# FILES: The binaries or scripts to install.
#
# Installs any executable file. $PATH will be automatically updated if the installation location is not currently in it.
function installExe() {
    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_EXES"

    # Update PATH
    updateEnv "PATH" "$prefix/bin"

    # Loop through every file
    for F in "$@"; do
        local name=`basename "$F"`
        local cmd=`command -v "$name" 2>&-`
        local apkg_dest1=`echo "$prefix/bin" | sed 's|//|/|g'`
        local apkg_dest2=`echo "$prefix/bin/.apkg-bins" | sed 's|//|/|g'`

        if [[ ! -f "$F" ]]; then
            warn "installExe: file $F not found in payload.";
            continue
        fi

        # Is such there an executable with the same name already in PATH?
        if command -v "$name" >&- 2>&- \
           && [[ "$cmd" != "$apkg_dest1/$name" ]]; then
            # Yes; create a bootstrap script to avoid conflicts

            copyFiles "$F" "$apkg_dest2"
            echo "#!/bin/sh
# Autopackage bootstrap script
# Name:    $SHORTNAME
# Package: $ROOTNAME
# Version: $VERSION
# $displayname

PATH=\"$prefix/bin:\$PATH\"
LD_LIBRARY_PATH=\"$prefix/lib:\$LD_LIBRARY_PATH\"
MANPATH=\"\$MANPATH:$prefix/share/man\"

export PATH LD_LIBRARY_PATH MANPATH

dir=\`dirname \"\$0\"\`
dir=\`cd \"\$dir\"; pwd\`
exec \"\$dir/.apkg-bins/$name\" \"\$@\"
" > "$prefix/bin/$name"
            chmod +x "$apkg_dest1/$name"
            echo "rm `escapeFilename \"$apkg_dest1/$name\"` 2>&-" >> "$apkg_logfile"
            echo "File $apkg_dest1/$name" >> "$apkg_filelist"
        else
            # No; copy this file & chmod +x it
            copyFiles "$F" "$apkg_dest1"
            chmod +x "$apkg_dest1/$name"
        fi
    done
    popOptE;
}


##
# installLib <LIBRARIES>
# LIBRARIES: The libraries to install.
#
# Install shared libraries (.so). The linker search path will be automatically updated.
function installLib() {
    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_LIB"
    local dest="$prefix/lib"

    trace dest is $dest
    if [[ `id -u` != "0" ]]; then
	trace updating LD_LIBRARY_PATH variable
	updateEnv "LD_LIBRARY_PATH" "$dest" --append
    fi

    # we put the uninstall instruction before the "rm" uninstall log entry is generated so it gets run after the library is removed :/
    echo '[[ `id -u == "0" ]] && /sbin/ldconfig' >> "$apkg_logfile"

    # copy the libraries
    copyFiles "$@" "$dest"

    # now setup the symlinks for the lib - ldconfig will remove dead symlinks for us on uninstall
    trace setting up symlinks in $dest
    /sbin/ldconfig -n "$dest"

    # make the .so symlink if one isn't already present for development....
    for l in $@; do
	local lname=$( basename $l | sed 's/\(.*\.so\).*/\1/' )
	local soname=$( objdump -x $l | grep SONAME | awk '{print $2}' )
	trace linking $dest/$soname to $dest/$lname
	if [ ! -e $dest/$soname ]; then 
	    ln -s "$dest/$soname" "$dest/$lname" # make the symlink for ld
	    echo "rm \"$dest/$lname\"" >> "$apkg_logfile"
	else
	    warn symlink already present
        fi
	
    done

    if [[ `id -u` == "0" ]]; then
	trace we are root
    	# scan the ld.so.conf file, is this directory in the cache? 
    	if ! grep "^$dest$" /etc/ld.so.conf >/dev/null; then
	    if [[ "$autopackage_update_linker_cache" == "true" ]]; then
		trace adding \$dest to ld.so.conf
	    	echo "$dest" >> /etc/ld.so.conf;
	    	# log it
	    	echo "removeLinkerCacheEntry '$dest'" >> "$apkg_logfile"
	    else
	    	# print a warning if installing to a prefix that isn't in the cache
	    	outputStatus "$intl_INSTALLING_PATH_NOT_IN_LINKER_CACHE";
	    fi
    	fi
	outputStatus "$intl_INSTALLING_UPDATING_LINKER  ";
	/sbin/ldconfig
    fi
    trace done
    popOptE;
}


##
# installMan <SECTION> <FILES>
# SECTION: The section these manpages belong to.
# FILES: The manpages to install.
#
# Install Unix manual pages. The manpage search path will be automatically updated.
function installMan() {
    pushOptE; set +e;
    if [[ $# -lt 2 ]]; then
        return 1
    fi

    outputStatus "$intl_INSTALLING_MAN"

    local section=$1
    shift

    if [[ "$autopackage_update_manpath" == "true" ]]; then
        if [[ `id -u` == "0" ]]; then
            # add path to the correct config file, either /etc/man.config or /etc/manpath.config
            if [ -e /etc/manpath.config ] && ! grep  -cE "MANDATORY_MANPATH $prefix/share/man" /etc/manpath.config &>/dev/null; then
                # If the file doens't ends with a newline, append it
                if ! endsWithNewline /etc/manpath.config; then
                    echo >> /etc/manpath.config
                fi
                echo "MANDATORY_MANPATH $prefix/share/man" >> /etc/manpath.config
            elif [ -e /etc/man.config ] && ! grep -cE "^MANPATH +$prefix/share/man$" /etc/man.config &>/dev/null; then
                # If the file doens't ends with a newline, append it
                if ! endsWithNewline /etc/man.config; then
                    echo >> /etc/man.config
                fi
                echo "MANPATH $prefix/share/man" >> /etc/man.config
            fi
            echo "removeManPath '$prefix/share/man'" >> "$apkg_logfile"
        else
            updateEnv "MANPATH" "$prefix/share/man" --append
        fi
    fi

    copyFiles "$@" "$prefix/share/man/man$section/"
    popOptE;
}


##
# installInfo <FILES>
# FILES: The .info file(s) to install.
#
# Install .info files.
function installInfo() {
    pushOptE; set +e;
    # Check for Info directory and Info file location
    if [[ `id -u` = "0" ]]; then
        info_dir="$prefix/share/info"
        info_dir_file="/usr/info/dir"
        [ -e "/usr/share/info" ] && info_dir_file="/usr/share/info/dir"
    else
        #info_dir="$prefix/share/info"
        unset info_dir
        unset info_dir_file
    fi

    if [ "$info_dir" ]; then
    
        outputStatus "$intl_INSTALLING_INFO"
    
        for F in "$@"; do
            local base=`basename "$F"`

            mkdirs "$info_dir"
            cp -f -p "$F" "$info_dir"

            # fixup the menu imports so they point to the correct prefix
            cat "$info_dir/$base" | sed "s|%PREFIX%|$info_dir|g" > "$info_dir/$base";
            gzip --best "$info_dir/$base"

            # give status like copyFiles function, update log and uninstall instructions
            outputStatus "`out \"$intl_INSTALLING_FILES\" \"$F\" \"$info_dir/$base.gz\"`"
            echo "uninstallInfo `escapeFilename \"$info_dir/$base\"`" >> "$apkg_logfile"
            echo "File $info_dir/$base" >> "$apkg_filelist"

            # install the info file
            pushd "`dirname \"$info_dir/$base.gz\"`" >/dev/null
            if locateCommand -o install-info --version | grep Debian; then
                cmd_to_run="`locateCommand -l install-info` \"$base\""
            elif test -w "$info_dir_file"; then
                cmd_to_run="`locateCommand -l install-info` --dir-file=\"$info_dir_file\" \"$base\""
            fi
            eval "$cmd_to_run"
            popd >/dev/null
        done
    
    fi
    popOptE;
}

##
# requireLibC <SYMBOL> [SYMBOL..]
# SYMBOL: A string of the form "GLIBC_2.1.3", but obviously adapted to the version reference that your binary needs
#
# requireLibC allows you to ensure that the system has at least the version of glibc that your binaries require.
# glibc does not break backwards compatability (in theory), it only ever adds interfaces. The reason this is 
# a separate function to require() is that glibc is a special pacakge - it is always present, and uses symbol
# versioning. 
#
# You can see which tag to use by running objdump on your binaries after they are compiled using the autopackage
# tools, and looking at the bottom of the output of `objdump -p binaryname`.
#
# This function sends front end test messages.
#
# Example:
# requireLibC GLIBC_2.0
function requireLibC() {
    pushOptE; set +e;
    if [[ "$@" == "" ]]; then return 0; fi; # we may be called with no arguments from backend.template, if no binaries are in the package
    outputTest "$intl_FUNCLIB_CHECKING_FOR_GLIBC_SYMBOL_VERSIONS"
    trace looking for $@
    local r
    r=`_checkForGlibcVersions $@` # can't use locals here due to bug in bash?
    if [[ $? != 0 ]]; then
	trace failed
	outputTestFail
	local msg=$( out "$intl_FUNCLIB_NEED_SYMBOLS" "`echo $r`" )
	outputFail "$msg"

#	unset _r
	popOptE;
	return 1
    else
	trace passed
	outputTestPass

#	unset _r
	popOptE;
	return 0
    fi
}


# installDesktopInitialize
#
# Initializes all available base desktop directory variables.
# This is an internal function and should not be used directly in scripts.
# <br><br>
# The following variables are initalized:
# <pre>
# $xdgdir                 - XDG base directory
# $xdgdir_mime            - XDG base MIME directory
# $desktop_file_install   - XDG .desktop install/validate software
# $dmsdir                 - Debian Menu System base directory
# $gnome1dir              - GNOME 1 base directory
# $gnome2dir              - GNOME 2 base directory
# $kde2dir                - KDE 2 & 3 base directory
# </pre>
function installDesktopInitialize() {
    if [[ "$__installDesktop_initialized" != "yes" ]]; then
        __installDesktop_initialized=yes
	trace called
        # Check for XDG Desktop Menu Specification   http://www.freedesktop.org/standards/
        if [ -e "/etc/desktop/menus/applications.menu" ] && [ "$DESKTOP_DIRS" ]; then
            if [[ `id -u` != "0" ]]; then
                if [ "$DESKTOP_USER_DIR" ]; then
                    xdgdir="$DESKTOP_USER_DIR"
                else
                    xdgdir="$HOME/.desktop"
                fi
            else
                xdgdir="/usr/share/applications"
            fi
        fi
	trace xdgdir=$xdgdir
        # Check for XDG Shared MIME-info Database   http://www.freedesktop.org/standards/
        if locateCommand update-mime-database; then
            if [[ `id -u` != "0" ]]; then
                if [ "$DESKTOP_USER_DIR" ]; then
                    xdgdir_mime="$DESKTOP_DATA_DIR/mime"
                else
                    xdgdir_mime="$HOME/.local/share/mime/"
                fi
            else
                xdgdir_mime="/usr/share/mime"
            fi
        fi
	trace xdgdir_mime=$xdgdir_mime
	
        # Check for XDG 'desktop-file-utils'   http://www.freedesktop.org/software/
        desktop_file_install=`locateCommand -l desktop-file-install`
        trace desktop_file_install=$desktop_file_install

        # Check for Debian Menu System [Mandrake]
        if locateCommand update-menus; then
            if [[ `id -u` != "0" ]]; then
                dmsdir="$HOME/.menu"
            else
                dmsdir="/usr/lib/menu"
            fi
        fi
	trace dmsdir=$dmsdir
	
        # Check for GNOME 1
        if locateCommand gnome-config --datadir; then
            gnome1dir="$lc_output/gnome"
        elif locateCommand panel; then
            gnome1dir="$lc_location"
            gnome1dir=`dirname "$gnome1dir"`/share/gnome
        fi
        if [ "$gnome1dir" ] && [[ `id -u` != "0" ]]; then
            gnome1dir="$HOME/.gnome"
        fi
	trace gnome1dir=$gnome1dir
	
        # Check for GNOME 2
        gnome2dir="`getGnome2Prefix`"
        if [[ "$gnome2dir" != "" ]]; then
            if [[ `id -u` = "0" ]]; then
                gnome2dir="$gnome2dir"
            else
                gnome2dir="$HOME/.gnome2"
            fi
        fi
	trace gnome2dir=$gnome2dir

        # Check for KDE 2 & KDE 3
        if locateCommand kde-config --prefix; then
            kdeversion=`kde-config --version | grep KDE: | awk -F'[ ]' '{ print $2 }'`

            # Check for KDE 3.2 & higher - if we want to block installation for KDE 3.2
            # REVERSE ORDER is necessary to compareVersion
            #if compareVersions 3.2 "$kdeversion"; then
            #    unset kde2dir

            # Check for KDE 2 & higher
            if compareVersions 2 "$kdeversion"; then
                kde2dir="$lc_output"

            fi
        elif locateCommand kicker; then
            kde2dir="$lc_location"
            kde2dir=`dirname "$kde2dir"`
        fi
        if [ "$kde2dir" ] && [[ `id -u` != "0" ]]; then
            kde2dir="$HOME/.kde"
        fi
	trace kde2dir=$kde2dir
    fi
}


##
# installDesktop <CATEGORY> <FILES>
# CATEGORY: The category the desktop entries belong to.
# FILES: The desktop entries to install.
# 
# Install a desktop entry (.desktop file). This function will
# automatically detect GNOME and KDE and will copy the desktop entires to
# the proper locations.

# Two methods given to support unified menu system from draft document.
# a - add 'Categories' key into Desktop Entry section and install into legacy locations
# b - add 'OnlyShowIn=Old;' into Desktop Entry section and install into legacy locations
#     remove 'OnlyShowIn=Old;' from Desktop Entry section and install into -datadir-/applications/
#
# A combination of case a and b will be used. It will install into all desktop
# locations that are available. This will maintain all compatibility combinations
# with desktops that are and are not using XDG DMS.
#
# For XDG DMS:
# Check/Add a 'Categories' key for proper XDG DMS display and install into determined
# -datadir-/applications/ locations. Therefore, a 'Categories' key is required.
#
# For Legacy desktops:
# Add 'OnlyShowIn=Old;' into Desktop Entry section and install into legacy locations.
# A .desktop file should not have the 'OnlyShowIn' key, the function will add it as needed.
#
# $DESKTOP_DIRS does not have to be set for valid XDG DMS - used until another method is found.
#
# Following 'Check' sections determine to what desktops to install by setting installation
# directory locations from base directories [installDesktopInitialize] while the 'Support'
# sections look for the directory locations independently and handle file, copy and log operations.
function installDesktop() {
    pushOptE; set +e; 
    local category="$1"
    shift

    outputStatus "$intl_INSTALLING_DESKTOP"

    # Initialize Base Desktop Directories
    trace initializing
    if [[ "$__installDesktop_initialized" != "yes" ]]; then installDesktopInitialize; fi

    for F in "$@"; do
        [[ ! -f "$F" ]] && warn "installDesktop: $F not found in payload."
    done

    # Setup for XDG
    if [ "$xdgdir" ]; then
        xdgdir_desktop="$xdgdir/applications"
    elif [ ! "$dmsdir" ]; then
        # Setup for DMS
	# Blocks GNOME, KDE desktops - need to block if needed - blackbox, enlightenment, WindowMaker

        # Setup for GNOME 1
        if [ "$gnome1dir" ]; then
            gnome1dir_desktop="$gnome1dir/apps"
        fi

        # Setup for GNOME 2
        if [ "$gnome2dir" ]; then
            if [[ `id -u` = "0" ]]; then
                gnome2dir_desktop="$gnome2dir/share/applications"
            else
                gnome2dir_desktop="$gnome2dir/vfolders/applications"
            fi
        fi

        # Setup for KDE 2 & KDE 3
        if [ "$kde2dir" ]; then
            kde2dir_desktop="$kde2dir/share/applnk"
        fi

    fi
    # XDG Desktop Menu Specification Support
    if [ "$xdgdir_desktop" ]; then
        # Install the desktop entry
	trace XDG support
        if [[ "$desktop_file_install" != "" ]]; then
            for F in "$@"; do
		trace $F
                local base=`basename \"$F\"`
                echo "rm `escapeFilename \"$xdgdir_desktop/apkg-$base\"` 2>&-" >> "$apkg_logfile"
                echo "File $xdgdir_desktop/apkg-$base" >> "$apkg_filelist"
            done
            # need to grab package vendor name like we do for $ROOTNAME from install script but without EXPORT
            # probably do not want to encourage adding categories outside of the spec with this method
	    trace calling the installer utility
            "$desktop_file_install" --vendor=apkg --dir="$xdgdir_desktop" --add-category="$category" "$@"
        else
	    trace no installer utility present, just copying files instead
            copyFiles "$@" "$xdgdir_desktop"
        fi

        #desktop-update-menus > /dev/null 2>&1

    fi

    # Debian Menu System Support [Mandrake]
    if [ "$dmsdir" ]; then
	trace debian menu support
        for F in "$@"; do

            local desktop=`getSection "$F" "Desktop Entry"`

            if [[ "$category" != "" ]]; then
                Section=`escapeValue "$category"`
            else
                Section=`escapeValue "/"`
            fi

            # pullout needed variables from $F .desktop file
            Exec=`echo "$desktop" | grep 'Exec=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            Icon=`escapeValue "$desktop" | grep 'Icon=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            Title=`escapeValue "$desktop" | grep '^Name=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            LongTitle=`escapeValue "$desktop" | grep 'Comment=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            MimeType=`escapeValue "$desktop" | grep 'MimeType=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
    
            # adjust 'Exec' value for a relocatable executable
            Exec="pdbrun $ROOTNAME $Exec"

            # keeping special characters [ " ; ' / ] usable for the 'Exec' and 'X-Autopackage' value
            Exec=`echo "$Exec" | sed 's|\/|\\\/|g; s|\"|\\\\\\\\"|g; s|\;|\\\\\\\\;|g'`
            XAutopackage=`echo "${ROOTNAME}" | sed 's|\/|\\\/|g; s|\"|\\\\\\\\"|g; s|\;|\\\\\\\\;|g'`

            # find and add some additional keys to 'kde_opt'
            DocPath=`escapeValue "$desktop" | grep 'DocPath=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            GenericName=`escapeValue "$desktop" | grep 'GenericName=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            InitialPreference=`escapeValue "$desktop" | grep 'InitialPreference=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            NoDisplay=`escapeValue "$desktop" | grep 'NoDisplay=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            OnlyShowIn=`escapeValue "$desktop" | grep 'OnlyShowIn=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            Path=`escapeValue "$desktop" | grep 'Path=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            Patterns=`escapeValue "$desktop" | grep 'Patterns=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            ServiceTypes=`escapeValue "$desktop" | grep 'ServiceTypes=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            Version=`escapeValue "$desktop" | grep 'Version=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XDCOPServiceType=`escapeValue "$desktop" | grep 'X-DCOP-ServiceType=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XKDELibrary=`escapeValue "$desktop" | grep 'X-KDE-Library=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XKDENativeMimeType=`escapeValue "$desktop" | grep 'X-KDE-NativeMimeType=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XKDEStartupNotify=`escapeValue "$desktop" | grep 'X-KDE-StartupNotify=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XKDESubstituteUID=`escapeValue "$desktop" | grep 'X-KDE-SubstituteUID=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            XKDEUsername=`escapeValue "$desktop" | grep 'X-KDE-Username=' | awk 'BEGIN{FS="="}; { print $2 }' -`;
            
            # menu output template
            menu="?package(local.$SHORTNAME):needs=\"x11\" section=\"%Section%\"  icon=\"%Icon%\" mimetypes=\"%MimeType%\" title=\"%Title%\" longtitle=\"%LongTitle%\" command=\"%Exec%\" kde_opt=\"\\\nDocPath=${DocPath}\\\nEncoding=UTF-8\\\nGenericName=${GenericName}\\\nInitialPreference=${InitialPreference}\\\nNoDisplay=${NoDisplay}\\\nOnlyShowIn=Old;${OnlyShowIn}\\\nPath=${Path}\\\nPatterns=${Patterns}\\\nServiceTypes=${ServiceTypes}\\\nVersion=${Version}\\\nX-Autopackage=$XAutopackage\\\nX-DCOP-ServiceType=${XDCOPServiceType}\\\nX-KDE-Library=${XKDELibrary}\\\nX-KDE-NativeMimeType=${XKDENativeMimeType}\\\nX-KDE-StartupNotify=${XKDEStartupNotify}\\\nX-KDE-SubstituteUID=${XKDESubstituteUID}\\\nX-KDE-Username=${XKDEUsername}\""

            # sub values into menu template
            menu=`echo "$menu" | sed "s/%Section%/${Section}/g"`
            menu=`echo "$menu" | sed "s/%Exec%/${Exec}/g"`
            menu=`echo "$menu" | sed "s/%Icon%/${Icon}/g"`
            menu=`echo "$menu" | sed "s/%Title%/${Title}/g"`
            menu=`echo "$menu" | sed "s/%LongTitle%/${LongTitle}/g"`
            menu=`echo "$menu" | sed "s/%MimeType%/${MimeType}/g"`
            menu=`echo "$menu" | sed "s/%KdeOptions%/${KdeOptions}/g"`

            # give status like copyFiles function along with mkdirs
            outputStatus "`out \"$intl_INSTALLING_FILES\" \"$F\" \"$dmsdir/$SHORTNAME\"`"
            mkdirs "$dmsdir"
            echo "$menu" >> "$dmsdir/$SHORTNAME"

        done
        # from the locateCommand above which was for update-menus
        if test -x "$lc_location"; then update-menus; fi

        # adding to logfile - delete the entire file if removing package
        echo "rm `escapeFilename \"$dmsdir/$SHORTNAME\"` 2>&-" >> "$apkg_logfile"
        echo "File $dmsdir/$SHORTNAME" >> "$apkg_filelist"

    fi # end of debian menus
    
    # GNOME 1 Support
    if [ "$gnome1dir_desktop" ]; then
        categorydir="$gnome1dir_desktop/$category"

        # determine if this is a Red Hat distribution - if yes then do some of the compatibility for XDG DMS
        if [ -e /etc/redhat-release ]; then
            match_distro=`cat /etc/redhat-release | grep "Red Hat"`
        fi
        
        # Red Hat 8 old menu merger workaround
        # added for compatibility to XDG DMS
        for F in "$@"; do
            copyFiles "$F" "$categorydir"
            removeSectionLine "$categorydir/`basename \"$F\"`" "Desktop Entry" "^Categories="
            if [ "$match_distro" ]; then
                addSectionLine "$categorydir/`basename \"$F\"`" "Desktop Entry" "OnlyShowIn=Old" "^OnlyShowIn="
            fi
            setupDesktopFile "$categorydir/`basename \"$F\"`"
        done
    fi

    # GNOME 2 Support
    if [[ "$gnome2dir_desktop" != "" ]]; then
        # Install the desktop entry
        for F in "$@"; do
	    local base=`basename "$F"`
	    local filename

	    if [[ "$desktop_file_install" = "" ]]; then
	    	trace "gnome2, invoking copyFiles"
	    	copyFiles "$F" "$gnome2dir_desktop"
	    	filename="$gnome2dir_desktop/$base"
	    else
	    	trace "gnome2, invoking $desktop_file_install"
	    	"$desktop_file_install" --vendor=apkg --dir="$gnome2dir_desktop" --add-category="$category" "$F"
	    	echo "rm `escapeFilename \"$gnome2dir_desktop/apkg-$base\"` 2>&-" >> "$apkg_logfile"
	    	echo "File $gnome2dir_desktop/apkg-$base" >> "$apkg_filelist"
	    	filename="$gnome2dir_desktop/apkg-$base"
	    fi

 	    setupDesktopFile "$filename"
        done
    fi

    # KDE 2 & KDE 3 Support
    if [ "$kde2dir_desktop" ]; then
        # Install the desktop entry
        if [[ "$desktop_file_install" != "" ]]; then
            trace "kde, invoking $desktop_file_install"
            for F in "$@"; do
                local base=`basename "$F"`
                echo "rm `escapeFilename \"$kde2dir_desktop/$category/apkg-$base\"` 2>&-" >> "$apkg_logfile"
                echo "File $kde2dir_desktop/$category/apkg-$base" >> "$apkg_filelist"
            done
            "$desktop_file_install" --vendor=apkg --dir="$kde2dir_desktop/$category" --add-category="$category" "$@"

            # added for compatibility to XDG DMS
            for F in "$@"; do
                local base=`basename "$F"`

                removeSectionLine "$kde2dir_desktop/$category/apkg-$base" "Desktop Entry" "^Categories="
                addSectionLine "$kde2dir_desktop/$category/apkg-$base" "Desktop Entry" "OnlyShowIn=Old" "^OnlyShowIn="
                setupDesktopFile "$kde2dir_desktop/$category/apkg-$base"
            done
        else
            trace "kde, invoking copyFiles"
            copyFiles "$@" "$kde2dir_desktop/$category"

            # added for compatibility to XDG DMS
            for F in "$@"; do
                local base=`basename "$F"`

                removeSectionLine "$kde2dir_desktop/$category/$base" "Desktop Entry" "^Categories="
                addSectionLine "$kde2dir_desktop/$category/$base" "Desktop Entry" "OnlyShowIn=Old" "^OnlyShowIn="
                setupDesktopFile "$kde2dir_desktop/$category/$base"
            done
        fi
    fi
    popOptE;
}


# setupDesktopFile
#
# Final setup process for .desktop file for use by desktop
# Modify and or add 'X-Autopackage' key to desktop files and add action menu
# to desktop files. Modify 'Exec' key to enable relocation of packages
function setupDesktopFile() {
    F="$1"

    addSectionLine "$F" "Desktop Entry" "X-Autopackage=${ROOTNAME}" "^X-Autopackage="

    exec_value=`getSection "$F" "Desktop Entry" | grep '^Exec=' | awk 'BEGIN{FS="="}; { print $2 }' -`
    if [ "$exec_value" ]; then
        addSectionLine "$F" "Desktop Entry" "Exec=pdbrun $ROOTNAME $exec_value" "^Exec="
    fi

    # add action menu text to .desktop file
    outn "$DESKTOP_ACTION_UPDATE" "$SHORTNAME" >> "$F";
    outn "$DESKTOP_ACTION_VERIFY" "$SHORTNAME" >> "$F";
    outn "$DESKTOP_ACTION_REMOVE" "$SHORTNAME" >> "$F";

    # gather previous 'Actions' values from Desktop Entry section and prepend new action values
    action_value=`getSection "$F" "Desktop Entry" | grep '^Actions=' | awk 'BEGIN{FS="="}; { print $2 }' -`
    addSectionLine "$F" "Desktop Entry" "Actions=Apkg-Update;Apkg-Verify;Apkg-Remove;$action_value" "^Actions="
}


##
# installIcon <FILES>
# FILES: The icon files to install.
#
# Install files to proper desktop icon directory.

# Implementation for XDG Icon Theme Specification   http://www.freedesktop.org/standards/
# Spec states standard [minimal] install to $icondir/hicolor/48x48/apps from ./share/icons/hicolor
# Implementation for XDG Base Directory Specification   http://www.freedesktop.org/standards/
#
# The XDG specifications listed are not harmonized dealing with user installs.
function installIcon() {
    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_ICON"

    if [ ! "$icondir" ]; then
        if [[ `id -u` = "0" ]]; then
            # XDG Icon Theme Specification
            # XDG Base Directory Specification
            icondir="/usr/share/icons"
        else
            # XDG Base Directory Specification
            if [ "$XDG_DATA_DIRS" ]; then
                if [ "$XDG_DATA_HOME" ]; then
                    icondir="$XDG_DATA_HOME/share/icons"
                else
                    icondir="$HOME/.local/share/icons"
                fi
            # XDG Icon Theme Specification
            else
                icondir="$HOME/.icons"
            fi
        fi
    fi

    copyFiles "$@" "$icondir/$SHORTNAME"
    popOptE;
}


##
# installSound <FILES>
# FILES: The sound files to install.
#
# Install files to proper desktop sound directory.
#
# Example:
# installSound ./share/sounds

# Premise is that sound will be similar to the handling of icons.
# Implementation represented from XDG Icon Theme Specification   http://www.freedesktop.org/standards/
# Implementation for XDG Base Directory Specification   http://www.freedesktop.org/standards/
#
# The XDG specifications listed are not harmonized dealing with user installs.
function installSound() {
    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_SOUND"

    if [ ! "$sounddir" ]; then
        if [[ `id -u` = "0" ]]; then
            # XDG Icon Theme Specification
            # XDG Base Directory Specification
            sounddir="/usr/share/sounds"
        else
            # XDG Base Directory Specification
            if [ "$XDG_DATA_DIRS" ]; then
                if [ "$XDG_DATA_HOME" ]; then
                    sounddir="$XDG_DATA_HOME/share/sounds"
                else
                    sounddir="$HOME/.local/share/sounds"
                fi
            # XDG Icon Theme Specification
            else
                sounddir="$HOME/.sounds"
            fi
        fi
    fi

    copyFiles "$@" "$sounddir/$SHORTNAME"
    popOptE;
}


##
# installIconTheme <NAME> <FILES>
# NAME: The name of the icon theme.
# FILES: The icon theme files to install.
#
# Install files to proper desktop icon theme directory.
#
# Example:
# installIconTheme "artdeco" ./share/icons/artdeco

# Implementation for XDG Icon Theme Specification   http://www.freedesktop.org/standards/
# Implementation for XDG Base Directory Specification   http://www.freedesktop.org/standards/
#
# The XDG specifications listed are not harmonized dealing with user installs.
function installIconTheme() {
    pushOptE; set +e;
    local theme_name="$1"
    shift

    outputStatus "$intl_INSTALLING_ICON"

    # Initialize
    if [ ! "$iconthemedir" ]; then
        if [[ `id -u` = "0" ]]; then
            # Represented from XDG Icon Theme Specification
            # XDG Base Directory Specification
            iconthemedir="/usr/share/icons/$theme_name"
        else
            # XDG Base Directory Specification
            if [ "$XDG_DATA_DIRS" ]; then
                if [ "$XDG_DATA_HOME" ]; then
                    iconthemedir="$XDG_DATA_HOME/share/icons/$theme_name"
                else
                    iconthemedir="$HOME/.local/share/icons/$theme_name"
                fi
            # Represented from XDG Icon Theme Specification
            else
                iconthemedir="$HOME/.icons/$theme_name"
            fi
        fi
    fi

    copyFiles "$@" "$iconthemedir/$theme_name"
    popOptE;
}


##
# getGnome2Prefix
# Outputs: A directory name, or nothing when GNOME 2 is not found.
#
# Get the prefix where GNOME 2 is installed to.
function getGnome2Prefix() {
    if locateCommand pkg-config "--exists gnome-vfs-2.2"; then
        echo "`pkg-config --variable=prefix gnome-vfs-2.0`"
        return 0
    elif locateCommand gnome-panel; then
        local gnome2dir="$lc_location"
        gnome2dir=`dirname "$gnome2dir"`
        gnome2dir=`dirname "$gnome2dir"`
        echo "$gnome2dir"
        return 0
    else
        return 1
    fi
}


##
# installGnome2AppEntry <FILES>
# FILES: The .applications files to install.
#
# Install GNOME 2 application entry files (.applications).
function installGnome2AppEntry() {
    if [[ `id -u` = 0 ]]; then
        if getGnome2Prefix > /dev/null; then
            local dir="`getGnome2Prefix`/share/application-registry"
        else
            return
        fi
    else
        local dir="$HOME/.gnome/application-info"
    fi
    copyFiles "$@" "$dir"
}


##
# installGnome2Mime <FILES>
# FILES: The .mime or .keys files to install.
#
# Install GNOME 2 MIME entries (.mime/.keys).
function installGnome2Mime() {
    if [[ `id -u` = 0 ]]; then
        if getGnome2Prefix > /dev/null; then
            local dir="`getGnome2Prefix`/share/mime-info"
        else
            return
        fi
    else
        local dir="$HOME/.gnome/mime-info"
    fi
    copyFiles "$@" "$dir"
}

# -------------------------------------------------------------

##
# removeDir <DIRECTORY>
# DIRECTORY: The directory to remove.
# Returns: 0 if DIRECTORY is removed, 1 otherwise.
#
# Recursively check if DIRECTORY is empty, and remove it if it is.
#
# See also: dirIsEmpty()
function removeDir()
{
    if dirIsEmpty "$1"; then
        rm -rf "$1"
        return $?
    else
        return 1
    fi
}

# called from an uninstall script to eliminate a linker cache entry
function removeLinkerCacheEntry() {
    entry=`escapeValue $1`
    sed "/$entry/d" /etc/ld.so.conf > /etc/ld.so.conf.new
    rm /etc/ld.so.conf
    mv /etc/ld.so.conf.new /etc/ld.so.conf
    unset entry
}

# $1 = path name
function removeManPath()
{
    if ! dirIsEmpty "$1"; then # we don't want to remove the manpath if other programs are using it
        return 1
    fi

    if [ -w /etc/man.config ]; then
      safeSed /etc/man.config "/^MANPATH `escapeValue $1`$/d"
    fi
    if [ -w /etc/manpath.config ]; then
      safeSed /etc/manpath.config "/^MANDATORY_MANPATH `escapeValue $1`$/d"
    fi
    
    return 0
}

function uninstallInfo() {
    # ARGH!!! install-info is junk, so manually edit the dir file to avoid things being screwed up
    info_dir_location=/usr/info/dir
    [ -e /usr/share/info/dir ] && info_dir_location=/usr/share/info/dir
    f=`echo "$1" | sed 's/\.info//'`
    l=`grep -n "$f" "$info_dir_location" | sed 's/:.*//'`
    if [[ "$l" != "" ]]; then
	# to avoid buffer conflicts we write to a variable then overwrite
	temp_buffer=`cat "$info_dir_location" | sed "${l}d"`
	echo "$temp_buffer" > $info_dir_location
    fi
    # delete the info file itself
    rm "$f.info.gz"
}

# -------------------------------------------------------------

##
# _findGlibcVersions DIR
# DIR: The directory to scan.
# Outputs: A list of Glibc version symbols, separated by whitespace.
#
# Scan a directory recursively for binaries and generate a list
# of Glibc version symbols that the binaries require.
function _findGlibcVersions()
{
    # Check if files are ELF executables and output their
    # symbols
    function __scanFile()
    {
	while read; do
	    if file "$REPLY" | grep -q ELF; then
		objdump -p "$REPLY" | grep -E '0x[0-9]+.*GLIBC_' | sed 's/.*GLIBC_//'
	    fi
	done
    }

    function __addSymbol()
    {
	while read; do
	    echo -n "$REPLY "
	done
    }

    local symbols=$( find "$1" -perm -754 -type f | __scanFile | sort | uniq | __addSymbol )
    echo "$symbols" | sed 's/ $//'
    unset __scanFile
    unset __addSymbol
}

##
# _checkForGlibcVersions <VERSION-SYMBOL> [VERSION-SYMBOL...]
# VERSION-SYMBOL: An entry in the binaries verneed table, for instance GLIBC_2.3.1
# Outputs: Missing symbols, if any.
# Returns: non-zero if one or more of the given symbols are missing, zero if all are found.
#
# Checks the system C library for the given version symbols. The missing symbols, if any
# will be output to stdout.
function _checkForGlibcVersions() {
    local s;
    local found=0
    for s in "$@"; do
	if ! nm -D /lib/libc.so.6 | grep "^00000000 A ${s}" &>/dev/null; then found=1; echo "$s"; fi
    done
    return $found
}

# -------------------------------------------------------------


