# -*-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 import() 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.

##
# $PREFIX
#
# The path of the prefix to which the software is installed.

##
# prepareBuild [--src SRCDIR]
# SRCDIR: If your project uses out-of-tree source builds, then specify the source directory here (either an absolute path, or relative to makeinstaller's working directory). The working directory will be used as build directory.
#
# Configure and compile the source code, and install files to a temporary 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.
#
# Optimization flags will be set, by default it will use "-O2 -march=i586 -pipe".
#
# See also: $APKG_BUILD_SKIP_CONFIGURE, $APKG_BUILD_SKIP_MAKE, unprepareBuild()
#
# Example:
# [BuildPrepare]
# prepareBuild --enable-foofeature
function prepareBuild() {
    local __apkg_errors_file=`echo "${TMP}/apkg-build-errors.$$"`

    trace build_root=$build_root
    
    local _prefix=/usr/local
    local srcdir=./
    
    if [[ "$1" = "--src" ]]; then
        shift
        srcdir=$1
        shift
    fi
    
    # Make sure we have a clean working space. This is here so we
    # can double compile. Without this, the second time that [BuildPrepare] is run
    # automake will decide that it doesn't need to rebuild anything and the same
    # binaries will be packaged up twice.
    if [[ "$APKG_BUILD_SKIP_MAKE" != "1" ]]  && [ -f Makefile ] && [[ "$CXX2" != "" ]]; then
       if [[ "$APKG_BUILD_VERBOSE" != "0" ]]; then
           make clean
       else
           make clean >/dev/null 2>"$__apkg_errors_file"
       fi
    fi

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

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

	# Mike wanted to garbage collect unused functions but this breaks
	# pretty much all libglade apps.
	#export CFLAGS="-ffunction-sections $CFLAGS"
	#export CXXFLAGS="-ffunction-sections $CXXFLAGS"
	#export LDFLAGS="-Wl,--gc-sections"

	if locateCommand apgcc; then
            if [[ "$CC" == "" ]]; then export CC=apgcc; fi
	    if [[ "$CXX" == "" ]]; then export CXX=apg++; fi
	fi
	trace "running $srcdir/configure"
        if [[ "$APKG_BUILD_VERBOSE" == "0" ]]; then
            "$srcdir/configure" --prefix=$_prefix "$@" >/dev/null 2>"$__apkg_errors_file"
        else
            touch "$__apkg_errors_file"
	    echo
	    echo "configure" --prefix=$_prefix "$@"
            "$srcdir/configure" --prefix=$_prefix "$@"
        fi
        local exitCode=$?
        export CFLAGS="$oCFLAGS"
        export CXXFLAGS="$oCXXFLAGS"
	trace exitCode was $exitCode
        if [[ "$exitCode" == "0" ]]; then
	    if [ -n "$(<"$__apkg_errors_file")" ]; then
	        [[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_CONFIGURING"; green; out "$intl_DONE_WITH_WARNINGS"; normal;
	        cat "$__apkg_errors_file";
            else
		[[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_CONFIGURING"; green; out "$intl_DONE"; normal;
	    fi
        else
            [[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_CONFIGURING"; red; echo "$intl_FAILED";
            normal; cat "$__apkg_errors_file";
            exit 1;
        fi

    fi
    
    local libtool_fixed
	if [ -f libtool ]; then
		trace Fixing libtool...
		if [ -f "$autopackage_prefix/libexec/autopackage/fixlibtool" ]; then
			# autopackage is installed
			trace using installed directories and executing fixlibtool
			bash "$autopackage_prefix/libexec/autopackage/fixlibtool" > libtool-fixed
		elif [ -f "$autopackage_prefix/libexec/fixlibtool" ]; then
			# autopackage is not installed
			trace using cvs directories and executing fixlibtool
			bash "$autopackage_prefix/libexec/fixlibtool" > libtool-fixed
		else
			warn fixlibtool could not be found.
		fi
		chmod +x libtool-fixed
		libtool_fixed="`pwd`/libtool-fixed"
	fi

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

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

	trace running make
        if [[ "$APKG_BUILD_VERBOSE" != "0" ]]; then
	    echo
            touch "$__apkg_errors_file"
            make LIBTOOL="$libtool_fixed"
        else
            make LIBTOOL="$libtool_fixed" >/dev/null 2>"$__apkg_errors_file"
        fi

        if [[ "$?" == "0" ]]; then
            if [ -n "$(cat "$__apkg_errors_file")" ]; then
                [[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_MAKING";
		green; out "$intl_DONE_WITH_WARNINGS";
                normal; cat "$__apkg_errors_file"; echo;
            else
                [[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_MAKING";
		green; out "$intl_DONE"; normal;
            fi
        else
            [[ "$APKG_BUILD_VERBOSE" != "0" ]] && outn "$intl_MAKING"; red; echo "$intl_FAILED";
            normal; cat "$__apkg_errors_file"; echo;
            exit 1;
        fi;
    fi

    if [[ "$APKG_BUILD_ROOT" != "" ]]; then
        trace "APKG_BUILD_ROOT set, not running make install"
    else
        echo "" >"$__apkg_errors_file";
        outn "$intl_INSTALLING" "$build_root";

	local installcmd="/usr/bin/install"

	# optimize install: don't use the abi-install program if there are no patches
	# in the tree
	local patches=$( find -name '*.GCCABI*' )
	if [[ "$patches" != "" ]]; then
	    if [[ -f "$autopackage_prefix/libexec/autopackage/abi-install" ]]; then
	        # autopackage is installed
		installcmd="$autopackage_prefix/libexec/autopackage/abi-install"
	    elif [[ -f "$autopackage_prefix/libexec/abi-install" ]]; then
	        # autopackage is not installed
		installcmd="$autopackage_prefix/libexec/abi-install"
	    else
		red
		out "'abi-install' is not found, please check your autopackage installation."
		normal
		false
	    fi
	fi

	# if this install has been patched to support SELinux, disable it.
	# this can *significantly* improve install times on Fedora Core,
	# and isn't harmful as we throw away the security contexts the
	# moment we tar it up anyway

	if $installcmd --help | grep "preserve_context"; then
	    trace "disabling SELinux security context matching"
	    installcmd="$installcmd -P"
	fi

        trace running make install
        local retval
        if [[ "$APKG_BUILD_VERBOSE" != "0" ]]; then
            touch "$__apkg_errors_file"
            if ! echo "$build_root" | grep -q "${TMP}/apkg-build-root.*${_prefix}$"; then
                make DESTDIR="$build_root" LIBTOOL="$libtool_fixed" INSTALL="$installcmd" prefix=$_prefix install
            else
                local correct_build_root=`echo $build_root | sed "s|${_prefix}$||g"`
                make DESTDIR="$correct_build_root" LIBTOOL="$libtool_fixed" INSTALL="$installcmd" prefix=$_prefix install
            fi
        else
            if ! echo "$build_root" | grep -q "${TMP}/apkg-build-root.*${_prefix}$"; then
                make DESTDIR="$build_root" LIBTOOL="$libtool_fixed" INSTALL="$installcmd" prefix=$_prefix install >/dev/null 2>"$__apkg_errors_file"
            else
                local correct_build_root=`echo $build_root | sed "s|${_prefix}$||g"`
                make DESTDIR="$correct_build_root" LIBTOOL="$libtool_fixed" INSTALL="$installcmd" prefix=$_prefix install >/dev/null 2>"$__apkg_errors_file"
            fi
        fi
        retval=$?

        [ -f libtool ] && rm -f libtool-fixed

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

    # for unprepareBuild
    export _virtual_build_root="$build_root"
    
    # if prepareBuild() has been called previously, then it
    # will have already added /usr/local to $build_root...don't add it again
    if ! echo "$build_root" | grep -q "${TMP}/apkg-build-root.*${_prefix}"; then
        export build_root=`echo "$build_root/$_prefix" | sed 's|//|/|g'` # bump it to reflect the DESTDIR voodoo above
    fi
    trace new build_root is $build_root
    
    return 0
}


##
# unprepareBuild
#
# Cleanup the temporary build root direcory made by prepareBuild(). You should not call this if you didn't already call prepareBuild().
#
# Example:
# [BuildUnprepare]
# unprepareBuild
function unprepareBuild() {
    # clean up after packaging
    if [[ "$APKG_BUILD_ROOT" == "" ]]; then
        outn "$intl_CLEANING"
        rm -rf "$_virtual_build_root"
        green; out "   $intl_DONE"; normal;
    fi
    unset build_root
    unset _virtual_build_root
}


##
# _scanLDLibPath <LIBRARY>
# LIBRARY: The unversioned soname of the library to search for (eg, libfoo.so)
# Outputs: A list of found libraries, seperated by newline.
#
# Scan $LD_LIBRARY_PATH for shared 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
### START SCANLDLIBPATH
### Function is substituted from apkg-script-utils.
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
}
### END SCANLDLIBPATH


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

function _testForLib_munge() {
    while read; do
	echo $REPLY | awk -F. '{print $1 "." $2}'
    done
}

##
# isLibrary32 <LIBRARY>
# LIBRARY: File name of the library to check.
# Since: 1.2
#
# Check whether a library is 32-bit or not. If the library is 32-bit, 0 is
# returned. If the library isn't 32-bit 1 is returned. If an error occurs,
# 2 is returned.
### START ISLIBRARY32
function isLibrary32() {
    pushOptE; set +e;

    local lib=$1

    if [[ "$lib" == "" ]]; then
        err must specify path to library to be checked
        popOptE
        return 2
    fi

    if [[ ! -e "$lib" ]]; then
        err "library $lib does not exist"
        popOptE
        return 2
    fi

    local s=$( echo `od --address-radix=n --format=d2 --skip-bytes=4 --read-bytes=1 $lib` )
    if [[ "${s// /}" == "2" ]]; then
        popOptE
        return 1
    fi

    popOptE
    return 0
}
### END ISLIBRARY32


##
# testForLib [-v] [-i] LibraryName
# -v: Verbose mode. Print each version number out on stdout.
# -i: Print each unique interface version found on stdout.
# LibraryName: The library to check for. This should be an unversioned soname, for instance libfoo.so
#
# Check for the existance of a library. If -v is specified the version
# number of each version of the library will be printed in a space
# separated list on stdout. If -i is specified each version number will
# be truncated to fit the A.B form required of interface versions, and duplicates
# will be stripped. It is an error to specify both.
#
# Outputs: If -v is specified, a list of found library version numbers.
# Returns: 0 = passed, 1 = library not present.
#
# Example:
# $ testForLib libfoo.so && echo "libfoo.so was found on the system!"
# $ ls /usr/lib/libstdc++.so.*
# /usr/lib/libstdc++.so.2.7.2.8
# /usr/lib/libstdc++.so.2.8.0
# /usr/lib/libstdc++.so.2.9.dummy
# /usr/lib/libstdc++.so.5.0.3
# /usr/lib/libstdc++.so.5 -> libstdc++.so.5.0.3
# $ testForLib -v libstdc++.so
# 2.7.2.8 2.8.0 2.9.dummy 5.0.3
### START TESTFORLIB
### Function is substituted from apkg-script-utils.
function testForLib() {
    pushOptE; set +e;
    local verbose=false
    local verbose_i=false
    local lib=""

    while [[ "$1" != "" ]]; do
	case $1 in
	    -v ) verbose=true; shift;;
	    -i ) verbose_i=true; shift;;
	    *  ) lib=$1; shift;;
	esac
    done

    if $verbose && $verbose_i; then
	err "the -i and -v options are mutually exclusive"
	popOptE
	return 1
    fi

    if [[ "$lib" == "" ]]; then
	err must specify the library to check for
	popOptE
	return 1
    fi

    local cacheresult
    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
    trace liblist=$liblist

    # make sure that libraries in $liblist are only valid 32-bit libs
    local found_32bit=false

    local oIFS="$IFS"
    IFS=$'\n';

    local l
    local -a liblist_array
    liblist_array=($liblist);
    for l in "${liblist_array[@]}"; do
        if isLibrary32 "$l"; then
            found_32bit=true
            break;
        fi
    done

    IFS="$oIFS"

    trace $found_32bit

    if ! $found_32bit; then
        warn "only 64-bit libraries were found, returning 1"
        popOptE;
        return 1
    fi

    if ! $verbose && ! $verbose_i; then
	popOptE
	return 0
    fi

    # we want to loop over the results until we find a library that matches the required version
    (
    echo "$liblist" | while read; do
	trace REPLY=.${REPLY}.
        local lib_resolved=$( _resolveLink "$REPLY" )
	trace lib_resolved=$lib_resolved
        if $verbose || $verbose_i; then
            echo "$lib_resolved" | sed 's/^.*\.so.//';
        fi
    done
    ) | sort | uniq | if $verbose_i; then _testForLib_munge; else cat; fi

    popOptE;
    return 0;
}
### END TESTFORLIB

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

# called when the install script is done
function _installScriptFinished() {
    trace called
    # load and create package environment variables
    _createPackageEnvironmentFiles "$_meta_dir"

    # process trigger before _createDBEntry so trigger commands are after
    # file and directory removals in the log
    _processTriggers

    _createDBEntry
    echo "$DISPLAYNAME" >>"$WORKING_DIRECTORY/display-names"
    echo "$installsize" >>"$WORKING_DIRECTORY/install-sizes"
    echo "$FILETOTAL" >>"$WORKING_DIRECTORY/file-totals"
    terminateFE;
    exit 0;
}

function _prepareScriptFinished() {
    trace called
    echo "$ROOTNAME" >> "$WORKING_DIRECTORY/prepared-rootnames"
}

##
# _decompressPayload
#
# Switches to the payload directory, and decompresses the included
# tarball while sending progress bar data to the ui Deletes the
# payload data aftewards.
function _decompressPayload() {

    # 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)

    pushd "$_payload_dir" >/dev/null

    # determine encoding from payload extention
    if [ -f "payload.tar.lzma" ]; then
        if [ -f "$autopackage_prefix/libexec/autopackage/unlzma" ]; then
            trace using unlzma
            "$autopackage_prefix/libexec/autopackage/unlzma" "payload.tar.lzma" /dev/stdout | tar -xvm | ( while read a; do
                (( filecount++ ));
                progressBar "$filecount" "$FILETOTAL" "$intl_PROGRESSBAR_EXTRACTING_FILES" 1;
            done; )
        else
            err "Cannot continue without the unlzma program."
            rm payload.tar.*
            popd >/dev/null
            return 1
        fi
    else
        tar -xm --bzip2 -vf "payload.tar.bz2" | ( while read a; do
            (( filecount++ ));
            progressBar "$filecount" "$FILETOTAL" "$intl_PROGRESSBAR_EXTRACTING_FILES" 1;
        done; )
    fi

    rm payload.tar.*

    popd >/dev/null
}


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


##
# mkdirs --nolog --session <DIRECTORY>
# --nolog: do not log the function call.
# --session: log into session file.
# DIRECTORY: directory to create.
# Returns: 0, if directory exists or is created; >0, if not created with return code from mkdir.
#
# Create directories within the filesystem and will return error codes if directories
# are not created.
#
# Removal of these directories will occur from within the removeFile function such
# that mkdirs function will not be logged.
#
# Example:
# mkdirs /home/mike/some/new/dir
#   --> creates some/new/dir
#
function mkdirs() {
    pushOptE; set +e;

    local nolog="false"
    local session="false"
    while [[ "$1" != "" ]]; do
        case "$1" in
            "--nolog")      nolog="true"; shift;;
            "--session")    session="true"; shift;;
            *) break;;
        esac
    done

    local dir="$1"
    if [ -d "$dir" ]; then
        warn "$dir" dir already exists
        popOptE
        return 0
    fi

    mkdir -p "$dir"
    local r=$?

    # session or nolog as requested
    if ! $session; then
        logCommand --session "removeDir `escapeFilename \"${dir}\"`"
    fi
    if ! $nolog; then
        logDir "$dir"
    fi

    # use of -p always gives a $?==0 so test
    # that the directory exists now
    if [ ! -d "$dir" ]; then
        err "$dir" dir was not created
        popOptE
        return $r
    else
        trace created dir "$dir"
        popOptE
        return 0
    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 [--silent] [--nobackup] [--nolog] <SOURCE> [<SOURCE> ...] <DIRECTORY>
# --silent: do not generate UI output.
# --nobackup: do not backup files or directory if they exist in DIRECTORY
# --nolog: do not log the function call.
# SOURCE: file or directory to copy.
# DIRECTORY: destination directory to copy the source files to.
# Returns: 0 if SOURCE exists and is copied to DIRECTORY; 1 if SOURCE does not exist or copy fails.
#
# Copy one or more files to destination DIRECTORY. The filenames are logged
# and will be automatically removed at uninstallation. Wildcards can be used
# when function is called with file or directory arguments - exactly like a ls call.
#
# This function can make a backup if the destination DIRECTORY contains
# the SOURCE file name. The original file will be moved to the BACKUP
# environment variable location.
#
# If the --silent flag is passed, no UI output will be generated. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --noprogressbar flag is passed, no progress bar UI output will be
# generated. This option is primarily meant for internal usage from the other
# APIs.
#
# If the --nobackup flag is passed, function  will not create backups. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --nolog flag is passed, no logging output will be generated. This option
# is primarily meant for internal usage from the other APIs.
#
# Example:
# copyFiles hello.txt world.txt "$PREFIX/doc"
#   copy files to destination --> "$PREFIX/doc"
#
# copyFiles libexec/bin/*.exe "$PREFIX/libexec"
#   copy *.exe files in directory to destination   --> "$PREFIX/libexec"
#
# copyFiles libexec/bin/* "$PREFIX/libexec"
#   copy files in directory to destination         --> "$PREFIX/libexec"
#
# copyFiles libexec/bin "$PREFIX/libexec"
#   recursive copy of directory bin to destination --> "$PREFIX/libexec/bin"
#
function copyFiles() {

    trace called with $@
    pushOptE; set +e;

    local nobackup="false"
    local nolog="false"
    local silent="false"
    local noprogressbar="false"
    while [[ "$1" != "" ]]; do
        case "$1" in
            "--nobackup")        nobackup="true"; shift;;
            "--nolog")           nolog="true"; shift;;
            "--silent")          silent="true"; shift;;
            "--noprogressbar")   noprogressbar="true"; shift;;
            *) break;;
        esac
    done

    if [ $# -le 1 ]; then
        err must have at least two arguments: SOURCE and DIRECTORY
        popOptE
        return 1
    fi

    # copy everything but last argument to an array
    # and create directory location from that last argument
    local i index
    local location
    local -a args
    local count file_count=0 backup_count=0
    local -a files
    local line_length
    local ls_1R ls_1R_count total_file_count

    args=("$@")
    count=${#args[@]}
    (( count-- ))
    i=0
    while (( $i < count )); do
        files[$i]="${args[$i]}"
        (( i++ ))
    done
    location="${args[i]}"
    if [[ ${location:0:1} != "/" ]]; then
        location="`pwd`/${args[i]}"
    fi

    # send outputStatus the destination location such that if $location is the
    # same information, it will not be shown - mainly used between copyFile
    if ! $silent; then
        # check if a directory SOURCE was sent - add to display location
        if [ -d "${files[0]}" ]; then
            trace adding directory source to copyFiles __outputStatus_status and beautify
            __outputStatus_status=`basename "${files[0]}"`
            __outputStatus_status=`echo "$location/$__outputStatus_status" | sed 's|//|/|g; s|/./|/|g'`
            outputStatus $( out "$intl_INSTALLING_FILE" "$__outputStatus_status" )
        else
            __outputStatus_status=`echo "$location" | sed 's|//|/|g; s|/./|/|g'`
            __outputStatus_status="$location"
            outputStatus $( out "$intl_INSTALLING_FILE" "$location" )
        fi
    fi

    # fail if destination directory name exists as a filename - protect filesystem from giving this error
    if [ -f "$location" ]; then
        local f=`basename "$location"`
        local d=`dirname "$location"`
        err an existing filename \"$f\" matches the destination directory at \"$d\"
        popOptE
        return 1
    fi
    [ ! -d "$location" ] && mkdirs "$location"
    local oPWD="$PWD"

    # simulate copying to gather total_file_count for progressBar function
    if ! $noprogressbar; then
        index=0
        while (( "$index" < "$count" )); do

            local element=`echo "${files[$index]}"`
            local directory=`dirname "$element"`
            local filename=`basename "$element"`
            #trace dir:$directory file:$filename element:$element
            cd "$directory"

            # check that a SOURCE without a wildcard is present
            if [ `expr index "$filename" '*'` -eq "0" ]; then
                if [ ! -d "$filename" ] && [ ! -f "$filename" ]; then
                    trace SOURCE without wildcard
                    err SOURCE does not exist: $filename
                    popOptE
                    return 1
                fi
            fi

            if [ ! -d "$filename" ]; then
                # count single file
                (( total_file_count++ ))
                trace file: total_file_count=$total_file_count
            else
                # count directory files
                # quote filename as necessary because '.' is different than *
                if [[ "$filename" == "*" ]]; then
                    ls_1R=`ls -1AR $filename 2>/dev/null`
                    ls_1R_count=`ls -1ARF $filename 2>/dev/null | grep -v '^$' | grep -v ':$' | grep -v '\/$' | wc -l`
                else
                    ls_1R=`ls -1AR "$filename" 2>/dev/null`
                    ls_1R_count=`ls -1ARF "$filename" 2>/dev/null | grep -v '^$' | grep -v ':$' | grep -v '\/$' | wc -l`
                fi

                # sum total
                let "total_file_count = $total_file_count + $ls_1R_count"
                trace dir: total_file_count=$total_file_count

                if (( ls_1R_count < 0 )); then
                    trace SOURCE with wildcard
                    err SOURCE does not exist: $filename
                    popOptE
                    return 1
                fi

            fi

            (( index++ ))
            cd "$oPWD"
        done

        # bash will not keep file_count for the later while loop
        # initialize file_count to temp file
        echo -n "0" > "${TMP}/apkg-copyFiles"

    fi


    # reset index and no longer simulating
    index=0
    while (( "$index" < "$count" )); do
        local element=`echo "${files[$index]}"`
        local directory=`dirname "$element"`
        local filename=`basename "$element"`
        #trace dir:$directory file:$filename element:$element
        cd "$directory"

        if [ ! -d "$filename" ]; then
            # backup file if collision will occur
            if [ -e "$location/$filename" ] && ! $nobackup; then
                trace backing up file to $autopackage_db_location/$BACKUP/$location/$filename
                [ ! -d "$autopackage_db_location/$BACKUP/$location" ] && mkdirs --nolog --session "$autopackage_db_location/$BACKUP/$location"
                mv -f "$location/$filename" "$autopackage_db_location/$BACKUP/$location/$filename"
                logCommand "recoverFile `escapeFilename \"$location/$filename\"`"
                (( backup_count++ ))
            fi

            # copy single file

            if ! $noprogressbar; then

                # bash will not keep file_count for the later while loop
                # write file_count to temp file to retrieve later
                if [ -e "${TMP}/apkg-copyFiles" ]; then
                    file_count=`cat "${TMP}/apkg-copyFiles"`
                fi
                (( file_count++ ))
                echo -n "$file_count" > "${TMP}/apkg-copyFiles"

                (( total_file_count >= 4 )) && progressBar $file_count $total_file_count "$( out "$intl_PROGRESSBAR_COPYING" )"

            fi
            cp -f "$filename" "$location/$filename"
            ! $nolog && logFile "$location/$filename"
        else
            # quote filename as necessary because '.' is different than *
            if [[ "$filename" == "*" ]]; then
                ls_1R=`ls -1AR $filename 2>/dev/null`
            else
                ls_1R=`ls -1AR "$filename" 2>/dev/null`
            fi

            # interate over ls_1R such that $location/$directory/$line make the destination filename
            echo "$ls_1R" | while read; do
                line="$REPLY"
                #trace line=$line
                # skip blank lines
                if [ ! -n "$line" ]; then
                    continue
                fi

                # line ending in ':' should be a directory so scrub the ':' and test if
                # source is a directory - if a directory then index to next line with directory
                # or if filename then use line as filename that contains an ending ':'
                line_length=${#line}
                if [ `echo "$line" | grep -ce ":$"` -gt 0 ]; then
                    line_directory=${line:0:$line_length-1}
                    if [ -d "$line_directory" ]; then
                        #trace setting directory as $line_directory
                        directory="$line_directory"
                        continue
                    fi
                fi

                if [ ! -d "$directory/$line" ]; then
                    # backup file if collision will occur
                    if [ -e "$location/$directory/$line" ] && ! $nobackup; then
                        trace backing up file to $autopackage_db_location/$BACKUP/$location/$directory/$line
                        [ ! -d "`dirname "$autopackage_db_location/$BACKUP/$location/$directory/$line"`" ] && mkdirs --nolog --session "`dirname "$autopackage_db_location/$BACKUP/$location/$directory/$line"`"
                        mv -f "$location/$directory/$line" "$autopackage_db_location/$BACKUP/$location/$directory/$line"
                        logCommand "recoverFile `escapeFilename \"$location/$directory/$line\"`"
                        (( backup_count++ ))
                    fi
                    # make directory if necessary
                    [ ! -d "`dirname "$location/$directory/$line"`" ] && mkdirs --nolog --session "`dirname "$location/$directory/$line"`"
                    # copy file
                    #trace copied to $location/$directory/$line

                    if ! $noprogressbar; then
                        # bash will not keep file_count outside of this while loop
                        # write file_count to temp file to retrieve later
                        if [ -e "${TMP}/apkg-copyFiles" ]; then
                            file_count=`cat "${TMP}/apkg-copyFiles"`
                        fi
                        (( file_count++ ))
                        echo -n "$file_count" > "${TMP}/apkg-copyFiles"

                        (( total_file_count >= 4 )) && progressBar $file_count $total_file_count "$( out "$intl_PROGRESSBAR_COPYING" )"
                    fi

                    cp -f "$directory/$line" "$location/$directory/$line"
                    ! $nolog && logFile "$location/$directory/$line"
                fi
            done

        fi

        (( index++ ))
        cd "$oPWD"
    done

    # always try to remove file_count temp file
    removeFile "${TMP}/apkg-copyFiles"

    trace backup_count=$backup_count
    popOptE
    return 0

}


##
# copyFile [--silent] [--nobackup] [--nolog] <FILENAME-FROM> <FILENAME-TO>
# --silent: do not generate UI output.
# --nobackup: do not backup files if files exist in FILENAME-TO directory.
# --nolog: do not log the function call.
# FILENAME-FROM: path to the file name
# FILENAME-TO: path to the file name
# Returns: 0 if SOURCE exists and is copied; 1 if SOURCE does not exist or copy fails.
#
# The copyFile function allows you to copy a single file to a given destination filename.
# It can be used when you want to rename a file while also copying it. This
# function creates a backup file if the destination already exists.
#
# This function can make a backup if the destination directory contains
# the FILENAME-TO file name. The original file will be moved to the BACKUP
# environment variable location.
#
# If the --silent flag is passed, no UI output will be generated. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --nobackup flag is passed, function will not create backups. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --nolog flag is passed, no logging output will be generated. This option
# is primarily meant for internal usage from the other APIs.
#
# Example:
# copyFile share/welcome-en.png "$PREFIX/share/welcome.png"
function copyFile() {
    pushOptE; set +e;
    trace called with $1 $2

    local nobackup="false"
    local nolog="false"
    local silent="false"
    while [[ "$1" != "" ]]; do
        case "$1" in
            "--nobackup")   nobackup="true"; shift;;
            "--nolog")      nolog="true"; shift;;
            "--silent")     silent="true"; shift;;
            *) break;;
        esac
    done

    if [[ "$#" != "2" ]]; then
        err must have two arguments: FILENAME-FROM and FILENAME-TO
        popOptE
        return 1
    fi

    if [ ! -e "$1" ]; then
        err FILENAME-FROM does not exist: $1
        popOptE
        return 1
    elif [ ! -f "$1" ]; then
        err FILENAME-FROM must be a file: $1
        popOptE
        return 1
    fi

    local filename_from="$1"
    local filename_to="$2"

    if [[ ${filename_to:0:1} != "/" ]]; then
        filename_to="`pwd`/$filename_to"
    fi

    # FILENAME-TO can not be an existing directory
    if [ -d "$2" ]; then
        err FILENAME-TO exists as a directory: $1
        popOptE
        return 1
    fi
    local filename_to_dir=`dirname "$filename_to"`

    # send outputStatus the destination location such that if $filename_to_dir is the
    # same information, it will not be shown
    if ! $silent; then
        __outputStatus_status="$filename_to_dir"
        outputStatus $( out "$intl_INSTALLING_FILE" "$filename_to_dir" )
    fi

    # fail if destination directory name exists as a filename - protect filesystem from giving this error
    if [ -f "$filename_to_dir" ]; then
        local f=`basename "$filename_to_dir"`
        local d=`dirname "$filename_to_dir"`
        err an existing filename \"$f\" matches the destination directory at \"$d\"
        popOptE
        return 1
    fi
    [ ! -d "$filename_to_dir" ] && mkdirs "$filename_to_dir"

    trace filename_from=$filename_from
    trace filename_to=$filename_to

    # backup file if collision will occur
    if [ -f "$filename_to" ] && ! $nobackup; then
        trace backing up file to $autopackage_db_location/$BACKUP/$filename_to
        [ ! -d "$autopackage_db_location/$BACKUP/$filename_to_dir" ] && mkdirs --nolog --session "$autopackage_db_location/$BACKUP/$filename_to_dir"
        mv -f "$filename_to" "$autopackage_db_location/$BACKUP/$filename_to"
        logCommand "recoverFile `escapeFilename \"$filename_to\"`"
        trace backup file
    fi

    # copy file
    #trace copied to $filename_to
    cp -f "$filename_from" "$filename_to"
    ! $nolog && logFile "$filename_to"

    popOptE
    return 0
}


##
# recoverFile <FILENAME>
# FILENAME: file or directory to move back into filesystem.
# Returns: 0 always.
#
# Recovers file or directory from the package's BACKUP environment
# variable directory and moves it back into the filesystem.<p>
#
# recoverFile() is the companion to the copyFile() functions. During a
# copy process if the file exists, the previous file is moved to
# $autopackage_db/$BACKUP/&lt;mimic filesystem&gt;. The $BACKUP variable is set
# as `$ROOTNAME/backup'.
#
# See also: copyFiles(), copyFile(), linkFile().
#
# Example:
# copyFiles "foo" "/some/directory" collides with a pre-existing file
# # uninstall log would have the entry
# # recoverFile /some/directory/foo   and the colliding file
# # would be copied to $autopackage_db/$BACKUP/some/directory/foo
#
function recoverFile() {

    trace called with $@

    if [ ! -e "$autopackage_db_location/$BACKUP/$1" ]; then
        warn $autopackage_db_location/$BACKUP/$1 does not exist to recover
    else
        trace recovering $autopackage_db_location/$BACKUP/$1
        local location=`dirname "$1"`
        copyFiles --silent --nolog --nobackup "$autopackage_db_location/$BACKUP/$1" "$location"
    fi

    trace finished
    return 0

}


##
# linkFile  [--silent] [--nobackup] [--nolog] <TARGET> <LINK_NAME>
# --silent: do not generate UI output.
# --nobackup: do not backup files if files exist in DIRECTORY
# --nolog: do not log the copyFiles function call.
# TARGET: filename on which to link to.
# LINK_NAME: name of the link to the TARGET.
# Returns: 0 on success, 1 on error.
#
# Create the symbolic link LINK_NAME which points to TARGET.
# This link will be recorded in the uninstall log.
#
# This function is exactly like 'ln -s', except that it also
# adds a record to the uninstall log.
#
# If the --silent flag is passed, no UI output will be generated. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --nobackup flag is passed, function will not create backups. This option
# is primarily meant for internal usage from the other APIs.
#
# If the --nolog flag is passed, no logging output will be generated. This option
# is primarily meant for internal usage from the other APIs.
function linkFile() {
    pushOptE; set +e;
    trace called with $@

    local silent="false"
    local nolog="false"
    local nobackup="false"
    local file_count=0 backup_count=0
    while [[ "$1" != "" ]]; do
        case "$1" in
            "--silent")     silent="true"; shift;;
            "--nolog")      nolog="true"; shift;;
            "--nobackup")   nobackup="true"; shift;;
            *) break;;
        esac
    done

    local filename_from="$1"
    local filename_to="$2"

    if [[ ${filename_to:0:1} != "/" ]]; then
        filename_to="`pwd`/$filename_to"
    fi
    local filename_to_dir=`dirname "$filename_to"`

    # send outputStatus the destination location such that if $filename_to_dir is the
    # same information, it will not be shown
    if ! $silent; then
        __outputStatus_status="$filename_to_dir"
        outputStatus $( out "$intl_INSTALLING_LINK" "$filename_from" "$filename_to")
    fi

    [ ! -d "$filename_to_dir" ] && mkdirs "$filename_to_dir"

    # backup LINK_NAME if it exists
    # mike - disabled, see above
    if [ -e "$filename_to" ] && ! $nobackup; then
        if [ ! -d "$filename_to" ]; then
            trace backing up file to $autopackage_db_location/$BACKUP/$filename_to
            [ ! -d "$autopackage_db_location/$BACKUP/$filename_to_dir" ] && mkdirs --nolog --session "$autopackage_db_location/$BACKUP/$filename_to_dir"
            mv -f "$filename_to" "$autopackage_db_location/$BACKUP/$filename_to"
            ! $nolog && logCommand "recoverFile `escapeFilename \"$filename_to\"`"
            (( backup_count++ ))
        else
            warn Can not backup a directory
        fi
    fi

    ln -sf "$filename_from" "$filename_to" &>/dev/null
    r="$?"
    if [[ "$r" != "0" ]]; then
        popOptE
        return 1
    else
        ! $nolog && logFile "$2"
        popOptE
        return 0
    fi

}


# Write a bash script which updates the path.
function _updateBashEnv()
{
	local pathFile="$1"
	local bashPathFile
	local files
	declare -a files

	local IFS=
	if [[ `id -u` != "0" ]]; then
		files=("$HOME/.bashrc" "$HOME/.bash_profile")
		bashPathFile="$HOME/.config/autopackage/paths-bash"
	else
		files=("/etc/profile")
		if [[ -f /etc/bash.bashrc ]]; then
		    files[${#files[@]}]="/etc/bash.bashrc"
		else
		    files[${#files[@]}]="/etc/bashrc"
		fi
		bashPathFile="/etc/autopackage/paths-bash"
	fi

	##### BEGIN HEADER
	cat <<EOF > "$bashPathFile"
# Auto-generated file. DO NOT EDIT
if [[ "x\$BASH" == "x" ]]; then
	# Do not run in zsh or other shells
	return
fi

function __autopackage_addBashPath
{
	local name=\$1
	local path=\$2
	local append=\$3
	local kind
	local tmp
	local array
	declare -a array

	local IFS=':'
	array=(\${!name});
	for DIR in "\${array[@]}"; do
		if [[ "\$DIR" = "\$path" ]]; then
			return 0
		fi
	done

	if [[ "\${!name}" = "" ]]; then
		eval "export \$name=\"\$path\""
	elif \$append; then
		eval "export \$name=\\"\$path:\\\$\$name\""
	else
		eval "export \$name=\\"\\\$\$name:\$path\""
	fi
	return 0
}

EOF
	##### END HEADER

	IFS=$'\n'
	while read LINE; do
		kind="${LINE:0:1}"
		tmp="${LINE:2}"
		name=`echo "$tmp" | sed 's/	.*//'`
		path=`echo "$tmp" | sed 's/.*	//'`

		if [[ "$kind" = "#" ]]; then
			continue
		elif [[ "$kind" = "A" ]]; then
			# Append
			echo "__autopackage_addBashPath \"$name\" `escapeFilename \"$path\"` true" >> "$bashPathFile"
		elif [[ "$kind" = "P" ]]; then
			# Prepend
			echo "__autopackage_addBashPath \"$name\" `escapeFilename \"$path\"` false" >> "$bashPathFile"
		fi
	done < "$pathFile"

	# Make sure the file is included in the bash startup scrips
	IFS=
	for F in "${files[@]}"; do
		path=`escapeValue "[[ -f \"$bashPathFile\" ]] && . \"$bashPathFile\""`
		if [[ -f "$F" ]] && ! grep "^$path$" "$F" &>/dev/null; then
			addLine "$F" "[[ -f \"$bashPathFile\" ]] && . \"$bashPathFile\""
		fi
	done
}

##
# updateEnv [--append] [--check] <VARIABLE> <PATH>
# VARIABLE: The environment variable to set.
# PATH: The path to add to it.
# --check: This parameter is deprecated. Do not use.
# --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. It will only be removed on uninstall if
# the directory specified by the PATH parameter is empty.
# The modifications to the environment variables will be saved in various shell
# startup scripts.
#
# If the environment variable already contains the given path, nothing is done.
#
# Example:
# updateEnv --append PATH "/path/to/my/program/bin"
function updateEnv()
{
	pushOptE; set +e;

	# updateEnv saves changes to /etc/autopackage/paths (or ~/.config/autopackage/paths),
	# instead of writing to bashrc as it used to. A bash script, bash-paths, is created
	# from that file. bashrc is then modified to 'source' that file. This minimizes the
	# chance of screwing up bashrc (not that I've ever seen it happening, but some people
	# are overly paranoid) and makes it easier to support new shells.

	local append=false
	local check=true

	# Parse arguments
	while [[ ${1:0:2} == "--" ]]; do
		if [[ "$1" == "--append" ]]; then
			append=true;
		elif [[ "$1" == "--check" ]]; then
			check=true;
		else
			warn unknown parameter $1;
		fi
		shift
	done

	local name="$1"
	local dest="$2"
	local val=${!name}
	local oIFS="$IFS"
	local array
	local line
	local tmp
	local apkg_path_file
	declare -a array
	declare -a files

	# Check whether the path is already in the variable
	local alreadyInVariable=0
	if $check; then
		IFS=':';
		array=($val);
		for DIR in "${array[@]}"; do
			if [[ "$DIR" == "$dest" ]]; then
				trace $dest is already in $name
				alreadyInVariable=1
				break
			fi
		done
		IFS="$oIFS"
	fi

	# Save this path into our own special autopackage path file
	if [[ `id -u` != "0" ]]; then
		apkg_path_file="$HOME/.config/autopackage/paths"
	else
		apkg_path_file="/etc/autopackage/paths"
	fi

	if $append; then
		line="A	$name	$dest"
	else
		line="P	$name	$dest"
	fi

	local alreadyInFile=0
	if [[ -f "$apkg_path_file" ]]; then
		# Check whether this line is already in the path file
		tmp=`escapeValue "$line"`
		if grep "^$tmp$" "$apkg_path_file" &>/dev/null; then
			trace $dest already in path file
			alreadyInFile=1
		fi
	else
		# Create the header of the path file if file doesn't exist
		tmp=`dirname "$apkg_path_file"`
		if [[ ! -d "$tmp" ]]; then
			mkdirs "$tmp"
		fi

		echo '# Auto-generated file; DO NOT EDIT!!!' > "$apkg_path_file"
	fi

	if [[ $alreadyInFile = 0 ]]; then
		echo "$line" >> "$apkg_path_file"
	fi
	trace $dest added to $apkg_path_file
	if [[ "$alreadyInVariable" == "0" ]]; then
		if [[ "${!name}" = "" ]]; then
			eval "export $name=\"$dest\""
		elif $append; then
			eval "export $name=\"$dest:\$$name\""
		else
			eval "export $name=\"\$$name:$dest\""
		fi
	fi

	# The path file is not a shell script. Generate
	# shell scripts from the path files.
	_updateBashEnv "$apkg_path_file"

	# Finally, add an uninstall log
	logCommand "if dirIsEmpty `escapeFilename \"$dest\"`; then removeLine \"$apkg_path_file\" \"$line\"; _updateBashEnv \"$apkg_path_file\"; fi;"

	popOptE
	return 0
}

##
# installExe <FILENAMES>
# FILENAMES: The binaries or scripts to install.
#
# Installs an executable file to $PREFIX/bin.  $PATH will be
# automatically updated if $PREFIX/bin is not currently in it.  The
# file will be given execution permissions. If there is already an
# executable with the same name in the PATH, then this function will
# build a bootstrap script so the program is guaranteed that when it
# does execute, PATH, LD_LIBRARY_PATH and MANPATH will be set
# correctly for that PREFIX. This function operates in terms of
# copyFiles(), so the notes for that function apply here also.
function installExe() {
    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_EXE"
    local F

    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

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

    # Loop through every file
    for F in "$@"; do
        local name=`basename "$F"`
        local cmd=`command -v "$name" 2>/dev/null`
        local apkg_dest=`echo "$PREFIX/bin" | sed 's|//|/|g'`

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

        if isFileELF "$F"; then
	    # Check whether this binary can be linked
	    local ferr=`LC_ALL=C LD_BIND_NOW=1 LD_TRACE_LOADED_OBJECTS=1 PATH=".:$PATH" "$F" 2>&1 >/dev/null | grep -v 'no version information available'`
	    if [[ "$ferr" != "" ]]; then
		err "$F cannot be run on this system."
                # if this occurs we screwed up, because we should have caught the reason
                # it would not link earlier.

                # but don't return, as otherwise we can't analyze the problem later
	    fi
        fi

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

            warn there is already an executable with the same name in the path, building bootstrap script
            mkdirs --session "$apkg_dest"

            copyFile --silent "$F" "$apkg_dest/.proxy.$name"

            chmod +x "$apkg_dest/.proxy.$name"
            createBootstrapScript "$apkg_dest/.proxy.$name" "$apkg_dest/$name"
        else
            # No; copy this file & chmod +x it
            copyFile --silent "$F" "$apkg_dest/$name"
            chmod +x "$apkg_dest/$name"
        fi
    done
    popOptE;
}


##
# _prepareCxxBinaries
#
# Search for C++ binary patches and apply them if necessary.
# All C++ binary patches will be deleted before this function returns.
function _prepareCxxBinaries() {
    if [[ "$CXX_ABI" == "0" || "$CXX_ABI" == "1" ]]; then
        find -name "*.GCCABI?.PATCH" | xargs rm -f
        return
    fi

    local IFS=$'\n'
    local orig
    outputStatus "$intl_BACKEND_PREPARING_CPLUSPLUS"
    for PATCH in `find -name "*.GCCABI${CXX_ABI}.PATCH"`; do
        orig=`echo "$PATCH" | sed 's/\.GCCABI.\.PATCH$//'`
        bspatch "$orig" "$orig.TEMP" "$PATCH"
        mv "$orig.TEMP" "$orig"
        chmod +x "$orig"
    done

    find -name "*.GCCABI?.PATCH" | xargs rm -f
}


##
# installLib <LIBRARIES>
# LIBRARIES: The file names of the libraries to install.
#
# Install shared libraries (.so files) to $PREFIX/lib. If the path to install to is not in the linker
# configuration, then it will be updated. If installing as root, /etc/ld.so.conf will be altered and
# ldconfig rerun. If installing as user, updateEnv will be called to ensure that the destination
# appears in LD_LIBRARY_PATH.
# <p>
# If your project uses libtool, then you probably have the following files:
# <ul>
# <li>libfoo.so.1.2.3</li>
# <li>libfoo.so.1 (symlink to libfoo.so.1.2.3)</li>
# <li>libfoo.so (symlink to libfoo.so.1.2.3)</li>
# </ul>
# You are supposed to install libfoo.so.1.2.3, not the symlinks. installLib
# will automatically ensure that the symlinks libfoo.so and libfoo.so.1 are created.
#
# Example:
# installLib lib/*.so.*
function installLib() {
    pushOptE; set +e;

    if [[ "$PREFIX" == "" ]]; then
        err "PREFIX must be set for this function"
        return 1
    fi

    outputStatus "$intl_INSTALLING_LIB"
    local dest="$PREFIX/lib"

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

    logCommand "removeDir `escapeFilename \"$dest\"`;"

    local -a files
    local F
    local base
    files=("$@")

    # Copy the libraries
    for F in "${files[@]}"; do

        # do not process imported library symlinks
        if [ -h "$F" ]; then
            trace skipping symlink $F
            continue
        fi

        base=`basename "$F"`
        copyFile --silent "$F" "$dest/$base"
    done

    # 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....
    local l
    for l in "${files[@]}"; do
    	# libfoo.so
	local lname=$( basename "$l" | sed 's/\(\.so\).*/\1/' )
	trace lname=$lname
	# libfoo.so.0
	local soname=$( objdump -p "$l" | grep SONAME | awk '{print $2}' )

	if [[ "$soname" == "" ]]; then
	    continue
	fi

	# link libfoo.so.0 to libfoo.so
	if [[ -e "$dest/$soname" && ! -e "$dest/$lname" ]]; then
	    trace linking $dest/$soname to $dest/$lname
	    ln -s "$dest/$soname" "$dest/$lname" # make the symlink for ld
	    logFile "$dest/$lname"
	else
	    warn development 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
	    		addLine /etc/ld.so.conf "$dest"
	    		# log it
	    		logCommand "removeLinkerCacheEntry `escapeFilename \"$dest\"`"
	    	else
	    		# print a warning if installing to a prefix that isn't in the cache
	    		outputStatus "$intl_INSTALLING_PATH_NOT_IN_LINKER_CACHE";
				outputStatus "$intl_INSTALLING_PATH_NOT_IN_LINKER_CACHE_SOLUTION" "$dest";
			fi
    	fi
        # register ldconfig trigger
        _registerTrigger ldconfig

    fi
    trace done
    popOptE;
}


##
# installMan <SECTION> <FILENAMES>
# SECTION: The section these manpages belong to.
# FILENAMES: The manpages to install.
#
# Install Unix manual pages.
# Example:
# installMan 5 foobar.conf # install foobar.conf into section 5
#
# To install translated manpages, use copyFiles() to install everything:
# Example:
# copyFiles share/man "$PREFIX/share"
function installMan() {
    pushOptE; set +e;
    if [[ $# -lt 2 ]]; then
        return 1
    fi

    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

    local section=$1
    shift
    outputStatus $( outn "$intl_INSTALLING_MAN" "$section" )

    copyFiles --silent "$@" "$PREFIX/share/man/man$section"
    popOptE;
}


##
# installInfo <FILENAMES>
# FILENAMES: The .info file(s) to install.
#
# Install GNU TeXinfo files. The info dirfile will be updated as necessary.
function installInfo() {
    pushOptE; set +e;

    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

    trace called with $@

    # 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_file
    fi

    trace info_dir=$info_dir, info_dir_file=$info_dir_file

    if [ "$info_dir" ]; then

        outputStatus "$intl_INSTALLING_INFO"

        for F in "$@"; do
            local base=`basename "$F"`

            copyFiles --nolog --silent "$F" "$info_dir"

            # fixup the menu imports so they point to the correct prefix
            safeSed "$info_dir/$base" "s|%PREFIX%|$info_dir|g";
            if ! echo $info_dir/$base | grep -q '.gz$'; then # only gzip if they're not already
                gzip --best "$info_dir/$base"
                # push a filelist entry since adding a gz extension
                logFile "$info_dir/$base.gz"

                # update log and uninstall instructions
                logCommand "removeInfo `escapeFilename \"$info_dir/$base.gz\"`"
            else
                # file is already gzipped, don't bother to gzip it
                # push a filelist entry since adding a gz extension
                logFile "$info_dir/$base"
                # update log and uninstall instructions
                logCommand "removeInfo `escapeFilename \"$info_dir/$base\"`"
            fi

            # install the info file
            pushd "$info_dir" >/dev/null
            if locateCommand -o install-info --version 2>&1 | grep Debian >/dev/null; then
		trace "debian install-info detected"
                cmd_to_run="`locateCommand -l install-info` \"$base\""
            elif test -w "$info_dir_file"; then
		trace "standard gnu install-info detected"
                cmd_to_run="`locateCommand -l install-info` --dir-file=\"$info_dir_file\" \"$base\""
            fi
	    trace about to run $cmd_to_run
            eval "$cmd_to_run"
            popd >/dev/null
            trace "$cmd_to_run"
        done

    fi
    trace done
    popOptE;
}


##
# installConfig <FILENAMES>
# FILENAMES: configuration file(s) to install.
#
# Install configuration files into appropriate directory.
# <b>Do not use this function!</b> It's severely broken in
# it's current state and I'm ashmed of the fact that it even
# exists like this. :( This function will be either removed
# or improved in autopackage 1.4, but for now, do not use it.
function installConfig() {
    pushOptE; set +e;

    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set in order to use installConfig"; return 1; fi

    trace called with $@

    # Set configuration (etc) directory based on user
    etc_dir=`_userConfig_broken`

    if [ "$etc_dir" ]; then

        outputStatus "$intl_INSTALLING_CONFIG"

        for F in "$@"; do

            if [ -f "$F" ]; then

                local base=`basename "$F"`

                # copy file to database silently, write uninstall command using baselineFile function
                copyFiles --silent --nolog "$F" "$etc_dir"
                logCommand "baselineFile `escapeFilename \"$etc_dir/$base\"`"

                # Fixup absolute references by substituting in prefix
                safeSed "$etc_dir/$base" "s|%PREFIX%|$PREFIX|g";

                # update baseline file
                getFile --baseline "$etc_dir/$base" >> "$_meta_dir/baseline"
                r="$?"
                if [[ "$r" != "0" ]]; then
                    err running getFile function on \"$etc_dir/$base\"
                    return "$r"
                fi

            fi

        done

    fi
    trace done
    popOptE;
}


##
# removeFile <FILENAME>
# FILE: file to remove.
# Returns: 0 for all cases.
#
function removeFile() {
    pushOptE; set +e;

    rm -f "$1" >/dev/null

    popOptE
    return 0

}


##
# baselineFile <FILENAME>
# FILE: file to compare.
# Returns: 0 if FILE is processed; 1 if malformed function call.
#
# Process to compare two files and archive FILE if it is different
# from file information which is archived in a baseline file
# defined by $ROOTNAME/baseline.<p>
#
# baselineFile() is the companion to installConfig() function. During the
# installConfig, a MD5 of the original configuration file is added to the
# baseline file called $ROOTNAME/baseline. The logfile would have a
# baselineFile to determine how to handle this special file. During the
# uninstall, baselineFile() creates a MD5 of the configuration file to
# delete and compares it the baseline MD5. autopackage will archive
# configuration files that are different from installed files while
# deleting the configuration files if they match. So custom or modified
# configuration files will still exist in the system for reference
# purposes.<p>
#
# If files are different then FILE is archived to FILE.apkgsave .
# If FILE.apkgsave exists then FILE.apkgsave is moved to FILE.apkgsave.1
# and FILE is copied to FILE.apkgsave . With this method, if FILE
# is archived then FILE.apkgsave is the latest saved version. Archived
# version are then FILE.apkgsave.2, FILE.apkgsave.3, etc.
#
# See also: installConfig().
#
# Example:
# installConfig "etc/foo-config"
# # uninstall log would have either entry
# # baselineFile /home/user/.local/etc/foo-config
# #   or
# # baselineFile /etc/foo-config
#
function baselineFile() {
    pushOptE; set +e;

    trace called with $@

    # if not different than original file then delete
    # otherwise mv to .apkgsave if available and then version like FILE.apkgsave.1
    if _checkFile --md5 "$1"; then
        trace files match
    else
        # check if file exist and move the existing file with an appended index number
        trace archiving file $1
        if [ -f "$1.apkgsave" ]; then
           # infinite loop
           local i=0
           while true; do
                ((i++))
                if [ ! -e "$1.apkgsave.$i" ]; then
                    trace copying previous archive file to $1.apkgsave.$i
                    cp -f "$1.apkgsave" "$1.apkgsave.$i"
                    trace removing previous archive file $1.apkgsave
                    removeFile "$1.apkgsave"
                    break
                fi
            done
        fi
        trace copying archive file to $1.apkgsave
        cp -f "$1" "$1.apkgsave"
    fi
    removeFile "$1"
    local config_dir=`dirname "$1"`
    removeDir "$config_dir"
    trace done
    popOptE
    return 0
}


##
# 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 outputs to the current frontend.
#
# This function will typically be called for you by the autopackage framework before execution of the prep script.
# You should not need to call it yourself.
#
# 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_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_NEED_SYMBOLS" "`echo $r`" )
	outputFail "$msg"

	popOptE;
	return 1
    else
	trace passed
	outputTestPass

	popOptE;
	return 0
    fi
}


##
# _installMenuItemInitialize
#
# Initializes all available base desktop directory variables.
# This is an internal function and should not be used directly in scripts.
#
# The following variables are initalized:
#
# $xdgdir                 - XDG data base directory
# $xdgdir_mime            - XDG MIME base directory
# $desktop_file_install   - XDG .desktop install/validate software
# $dmsdir                 - Debian Menu System base directory
# $gnome2dir              - GNOME 2 base directory
# $kde2dir                - KDE 2 & 3 base directory
#
function _installMenuItemInitialize() {
    trace called

    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set in order to use _installMenuItemInitialize()"; return 1; fi;

    # Check for XDG Desktop Menu Specification   http://freedesktop.org/Standards/menu-spec/
    if [[ `id -u` != "0" ]]; then
        if [[ "$XDG_DATA_HOME" != "" ]]; then
            xdgdir="$XDG_DATA_HOME"
        else
            xdgdir="$HOME/.local/share"
        fi
    else
        xdgdir="$PREFIX/share"
    fi
    trace xdgdir=$xdgdir

    # Check for XDG Shared MIME-info Database   http://freedesktop.org/Standards/shared-mime-info-spec/
    xdgdir_mime="$xdgdir/mime"
    trace xdgdir_mime=$xdgdir_mime

    # Check for XDG 'desktop-file-utils'   http://freedesktop.org/Software/desktop-file-utils
    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
	    if [[ -e "/etc/mandrake-release" ]]; then
	       dmsdir="/usr/lib/menu"
	    else
	       dmsdir="/usr/share/menu" #debian and its derivatives prefer menu files in here
	    fi
        fi
    fi
    trace dmsdir=$dmsdir

    # Check for pre-XDG GNOME 2
    gnome2dir="`getGnome2Prefix`"
    if [[ "$gnome2dir" != "" ]]; then
        if ! ls "$gnome2dir"/lib/libgnome-menu.so.* &>/dev/null; then
            if [[ `id -u` == "0" ]]; then
                gnome2dir="$gnome2dir"
            else
                gnome2dir="$HOME/.gnome2"
            fi
        else
            trace "not using pre-xdg gnome2 support as libgnome-menu.so.2 was found"
            gnome2dir=""
        fi
    fi
    trace gnome2dir=$gnome2dir

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

    elif locateCommand kicker; then
        kde2dir="$lc_location"
        kde2dir=`dirname "$kde2dir"`
    fi

    if [ "$kde2dir" ] && [[ `id -u` != "0" ]]; then
        kde2dir="$HOME/.kde"
    fi

    # kde 3.3 and above use xdg menu - remove kde2 support
    if compareVersions "3.3" "$kdeversion"; then
      unset kde2dir
    fi

    trace kde2dir=$kde2dir

    __installMenuItem_initialized=true

}


##
# installDesktop
# Deprecated: 1.2
#
# See also: installMenuItem()
function installDesktop() {
    installMenuItem "$@"
}

##
# installMenuItem [--no-path-adjust] <CATEGORY> <FILENAMES>
# --no-path-adjust: Do not change paths in the .desktop file to absolute paths.
# CATEGORY: The category the desktop entries belong to.
# FILENAMES: The desktop entries to install.
# Since: 1.2
#
# Install a menu entry (.desktop file). This function will automatically
# detect GNOME and KDE and will copy the desktop entires to the proper
# locations.<br>
#
# By default, this function will change the paths in the TryExec, Exec
# fields to absolute filenames by prepending "$PREFIX/bin".
# For instance, "Exec=gimp" will be changed to "Exec=/home/myuser/.local/bin/gimp".<br>
#
# If you do not want installMenuItem to change the paths, pass the --no-path-adjust argument.
#
# The CATEGORY parameter is used for non-vFolder/menu spec desktops such as KDE 3.1 and below,
# and possibly in future window managers like fluxbox/icewm as well. You should probably
# specify a string that would fit with the pre-KDE 3.2 menus here, such as "Graphics/Vector Graphics"
#
# Example:
# installMenuItem "Network/Instant Messaging" gaim.desktop
function installMenuItem() {
    pushOptE; set +e;

    outputStatus "$intl_INSTALLING_DESKTOP"

    # Initialize Base Desktop Directories
    if ! ${__installMenuItem_initialized:-false}; then
        _installMenuItemInitialize
    fi

    local adjust_path=true
    if [[ "$1" == "--no-path-adjust" ]]; then
        adjust_path=false
        shift
    fi

    local category="$1"
    shift

    if [[ "$@" == "" ]]; then
        err "installMenuItem requires at least 2 arguments. Did you forget to specify the Category?"
        popOptE;
        return 1;
    fi

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

    # Setup for XDG
    if [[ "$xdgdir" != "" ]]; then
        xdgdir_desktop="$xdgdir/applications"
    fi

    # Setup for DMS
    # Blocks GNOME, KDE desktops - need to block if needed - blackbox, enlightenment, WindowMaker
    if [ ! "$dmsdir" ]; then

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

                # gnome2dir and xdgdir could be the same - check and clear xdg if necessary
                if [[ "$xdgdir_desktop" == "$gnome2dir_desktop" ]]; then
                    unset xdgdir_desktop
                    trace xdgdir_desktop and gnome2dir_desktop are the same, clearing xdgdir_desktop
                fi
            else
                gnome2dir_desktop="$gnome2dir/vfolders/applications"
            fi
        fi

        # Setup for KDE 2 & KDE 3
        if [ "$kde2dir" ]; then
            # Check for RedHat KDE
            if [[ -d /usr/share/applnk-redhat ]]; then
                kde2dir_desktop="$kde2dir/share/applnk-redhat"
            else
                kde2dir_desktop="$kde2dir/share/applnk"
            fi
        fi

    fi

    # XDG Desktop Menu Specification Support
    if [ "$xdgdir_desktop" ]; then
        # Install the desktop entry
        trace XDG support
        for F in "$@"; do
            local base=`basename "$F"`
            local filename="$xdgdir_desktop/$base"
            copyFiles --silent "$F" "$xdgdir_desktop"
            _setupDesktopFile $adjust_path "$filename"
        done
    fi

    # Debian Menu System Support
    if [ "$dmsdir" ]; then
        trace debian menu support

        for F in "$@"; do
            local section="$category"

            # Mandriva requires KControl modules and KDE screensavers to be in different places
            if [ -e /etc/mandrake-release ]; then
                section=`echo $section | sed 's/System\/ScreenSavers/.hidden\/ScreenSavers/'`
                section=`echo $section | sed 's/Settings\//System\/Configuration\/KDE\//'`
            fi

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

            if [[ -z `grep Terminal=true "$F"` ]]; then
                needs="x11"
            else
                needs="text"
            fi

            echo -n "?package(local.$SHORTNAME):needs=\"$needs\" section=\"$section\"" > "${TMP}/apkg-debiantmp1"
            echo -n " kde_opt=\"X-Autopackage=${ROOTNAME}\\\n" > "${TMP}/apkg-debiantmp2"

            # Go through each line of the file
            cat "$F" |
            while read line
            do
                if [ "${line:0:1}" == "[" ]; then
                    sectionName=$line
                fi
                if [ "$sectionName" != "[Desktop Entry]" ]; then
                    echo -n "$line\\\n" >> "${TMP}/apkg-debiantmp2"
                    continue
                fi
                if [ "$line" == "[Desktop Entry]" ]; then
                    continue
                fi

                local key=`echo $line | awk 'BEGIN{FS="[ \t]*=[ \t]*"}; { print $1 }'`
                local value=`echo $line | awk '{ match($0, "[ \t]*=[ \t]*"); print substr($0, RSTART+RLENGTH) }' | sed 's/\"/\\\"/'`

                if [ "${#key}" -le "0" ]; then
                    continue
                fi

                case "$key" in
                    "Name" ) echo -n " title=\"$value\"" >> "${TMP}/apkg-debiantmp1" ;;
                    "Exec" ) echo -n " command=\"$value\"" >> "${TMP}/apkg-debiantmp1" ;;
                    "Icon" ) echo -n " icon=\"$value\"" >> "${TMP}/apkg-debiantmp1" ;;
                    "Comment" ) echo -n " longtitle=\"$value\"" >> "${TMP}/apkg-debiantmp1" ;;
                    "MimeType" ) value=`echo "$value"|sed 's/;/,/'`;echo -n " mimetypes=\"$value\"" >> "${TMP}/apkg-debiantmp1" ;;
                    "Categories" ) ;;
                    * ) echo -n "$key=$value\\\n" >> "${TMP}/apkg-debiantmp2" ;;
                esac
            done

            echo "\"" >> "${TMP}/apkg-debiantmp2"
            read
            mkdirs "$dmsdir"
            cat "${TMP}/apkg-debiantmp1" "${TMP}/apkg-debiantmp2" >> "$dmsdir/$SHORTNAME"
            trace added debian menu entry to "$dmsdir/$SHORTNAME"
            rm -f "${TMP}/apkg-debiantmp1" "${TMP}/apkg-debiantmp2"

        done

        # adding to logfile - delete the entire file if removing package
        logFile "$dmsdir/$SHORTNAME"

        # register update-menus trigger
        _registerTrigger menus

    fi # end of debian menus

    # GNOME 2/vfolder 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 --silent "$F" "$gnome2dir_desktop"
	    	filename="$gnome2dir_desktop/$base"
	    else
	    	trace "gnome2, invoking $desktop_file_install"
	    	"$desktop_file_install" --vendor=apkg --dir="$gnome2dir_desktop" "$F" 1>>"$AUTOPACKAGE_DEBUG_LOGFILE" 2>>"$AUTOPACKAGE_DEBUG_LOGFILE"
	    	logFile "$gnome2dir_desktop/apkg-$base"
	    	filename="$gnome2dir_desktop/apkg-$base"
	    fi

	    _setupDesktopFile $adjust_path "$filename"

            # we need to mangle the ~/.gnome2/vfolders/applications.vfolder-info file
            # This hack is only needed for some user installs
            if [ `id -u` != "0" ]; then
                local categories=$( awk '/(Categories[ \t]*=[ \t]*)([^ ]*)/ {print $1}' $filename )
                if [ -z "$categories" ]; then
                    err "No categories specified in desktop file"
                else
                    categories=$( echo $categories | sed -e 's/Categories[ \t]*=[ \t]*\(.*\)$/\1/' )
                    categories=$( echo $categories | sed -e 's/;/ /g' )

                    # Determine gnome configuration prefix.
                    # I don't know if gnome-config can always be found on any
                    # gnome installation. Defaulting to /etc if not.
                    local gnome_config=`locateCommand -o gnome-config --sysconfdir`
                    if [ -n "$gnome_config" ]; then
                        local sysconfdir="$gnome_config"
                    else
                        local sysconfdir="/etc"
                    fi
                    trace gnome config sysconfdir: $sysconfdir

                    # register vfolder trigger
                    _registerTrigger vfolder "\"$filename\" \"$sysconfdir\" $categories"
                fi
            fi
        done
    fi

    # KDE 2 & KDE 3 Support
    if [ "$kde2dir_desktop" ]; then

        # Change source desktop file for a KDE installation
        local desktop_entry_section=$( getSection "$F" "Desktop Entry" )
        local cat_count=$( echo "$desktop_entry_section" | grep -c '^Categories' )
        if (( cat_count == 1 )); then
            local categories_value=`echo "$desktop_entry_section" | grep '^Categories=' | awk 'BEGIN{FS="="}; { print $2 }' -`
            local i=${#categories_value}
            (( i-- ))
            if [[ ${categories_value:$i} != ";" ]]; then
                trace adding ';' to Desktop Entry Categories values in $F
                addSectionLine "$F" "Desktop Entry" "Categories=${categories_value};" "^Categories="
                # reload categories_value
                desktop_entry_section=$( getSection "$F" "Desktop Entry" )
                categories_value=`echo "$desktop_entry_section" | grep '^Categories=' | awk 'BEGIN{FS="="}; { print $2 }' -`
            fi
            if echo "$categories_value" | grep -qF "Core;" && ! echo "$categories_value" | grep -qF "KDE;"; then
                trace adding KDE to $F
                addSectionLine "$F" "Desktop Entry" "Categories=${categories_value}KDE;" "^Categories="
            fi
        elif (( cat_count > 1 )); then
            err "installMenuItem: desktop file $F has more than 1 'Categories' keys in the Desktop Entry section."
        fi

        # Install the desktop entry
        if [[ "$desktop_file_install" != "" ]]; then
            trace "kde, invoking $desktop_file_install"
            for F in "$@"; do
                local base=`basename "$F"`
                logFile "$kde2dir_desktop/$category/apkg-$base"
            done
            "$desktop_file_install" --vendor=apkg --dir="$kde2dir_desktop/$category" --add-category="$category" "$@" >> "$AUTOPACKAGE_DEBUG_LOGFILE" 2>> "$AUTOPACKAGE_DEBUG_LOGFILE"

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

                #removeSectionLine "$kde2dir_desktop/$category/apkg-$base" "Desktop Entry" "^Categories="
                _setupDesktopFile $adjust_path "$kde2dir_desktop/$category/apkg-$base"
            done
        else
            trace "kde, invoking copyFiles"
            copyFiles --silent "$@" "$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="
                _setupDesktopFile $adjust_path "$kde2dir_desktop/$category/$base"
            done
        fi

    fi

    # if kde window manager is running then force reload of desktop files
    # register kbuildsycoca trigger
    _registerTrigger kbuildsycoca

    # keep the paths around for the summary screen at the end
    echo "$@" | while read; do
        local F
        for F in $REPLY; do
	    if [[ ${F:0:1} == "." ]] || [[ ${F:0:1} != "/" ]]; then
	        # make absolute
	        F="`pwd`/$F"
	    fi
	    echo "$F" >>"$WORKING_DIRECTORY/desktop-files"
        done
    done
    popOptE;
    return 0;
}


##
# _logTrigger
#
# Log command based on trigger such that the command will
# execute during uninstall.
function _logTrigger() {

    shift
    trace called with $@
    local directory level

    case "$1" in
        ldconfig )
                        # no need to log command as this originates from removeLinkerCacheEntry
                        ;;

        desktop )
                        logCommand "locateCommand -r update-desktop-database -q"
                        ;;

        kbuildsycoca )
                        logCommand "[[ \`id -u\` != \"0\" ]] && [[ \`ps ax | grep -c \"[ ]kwin\"\` != \"0\" ]] && locateCommand -r kbuildsycoca &>/dev/null;"
                        ;;

        mime )
                        shift
                        logCommand "[ ! -d \"$@/packages\" ] && rm -rf \"$@\" && removeDir \"$@\"; locateCommand -r update-mime-database \"$@\" &>/dev/null;"
                        ;;

        menus )
                        logCommand "locateCommand -r update-menus &>/dev/null"
                        ;;

        vfolder )
                        shift
                        logCommand "\"$autopackage_prefix/libexec/autopackage/vfolder-magic\" uninstall \"$HOME/.gnome2/vfolders/applications.vfolder-info\" $1 $2"
                        ;;

        icon )
                        ;;

    esac
    return 0

}


##
# _registerTrigger
#
# Writes the trigger method to file to execute commands and
# write uninstall log entries. Levels are included in command
# file to order commands like kbuildsycoca should always be
# last.
function _registerTrigger() {

    trace called with $@
    local method level extra

    method="$1"
    shift

    case "$method" in
        ldconfig )
                        level="1"
                        ;;

        desktop )
                        level="6"
                        ;;

        kbuildsycoca )
                        level="7"
                        ;;

        mime )
                        level="4"
                        [ -z "$xdgdir_mime" ] && _installMenuItemInitialize
                        extra=`escapeFilename "$xdgdir_mime"`
                        ;;

        menus )
                        level="3"
                        ;;

        vfolder )
                        level="2"
                        extra="$@"
                        ;;

        icon )
                        level="5"
                        extra="$@"
                        ;;

    esac
    echo "$level $method $extra" >> "$WORKING_DIRECTORY/delayed-commands-package"
    return 0

}


##
# _executeTrigger
#
# Executes trigger related to method. These commands execute at the
# end of the installation session after summary screen is generated.
function _executeTrigger() {

    trace called with $@
    shift

    case "$1" in
        ldconfig )
                        [[ `id -u` == "0" ]] && /sbin/ldconfig
                        ;;

        desktop )
                        if locateCommand update-desktop-database; then
                            if ! "$lc_location" "$PREFIX/share/applications" -q; then
                                err update-desktop-database failed
                            fi
                        else
                            warn update-desktop-database not found
                        fi
                        ;;

        kbuildsycoca )
                        if [[ `id -u` != "0" ]] && [[ `ps ax | grep -c "[ ]kwin"` != "0" ]]; then
                            trace found kwin ... running kbuildsycoca
                            locateCommand -r kbuildsycoca &>/dev/null
                        fi
                        ;;

        mime )
                        shift
                        if locateCommand update-mime-database; then
                            "$lc_location" "$@" &>/dev/null
                        else
                            warn update-mime-database was not found
                        fi
                        ;;

        menus )
                        if locateCommand update-menus; then
                            "$lc_location" 1>>"$AUTOPACKAGE_DEBUG_LOGFILE" 2>>"$AUTOPACKAGE_DEBUG_LOGFILE"
                        else
                            warn update-menus was not found
                        fi
                        ;;

        vfolder )
                        shift
                        "$autopackage_prefix/libexec/autopackage/vfolder-magic" install "$HOME/.gnome2/vfolders/applications.vfolder-info" $@
                        ;;

        icon )
                        shift
                        if locateCommand gtk-update-icon-cache; then
                            if [ -n "$1" ]; then
                                for D in "$@"; do
                                    # check for theme cache file - if not present use --ignore-theme-index
                                    if [ -f "$D/hicolor/icon-theme.cache" ]; then
                                        trace running gtk-update-icon-cache with theme index $D/hicolor
                                        gtk-update-icon-cache --quiet "$D/hicolor" &>/dev/null
                                    else
                                        trace running gtk-update-icon-cache without theme index "$D/hicolor"
                                        gtk-update-icon-cache --quiet --ignore-theme-index "$D/hicolor" &>/dev/null
                                    fi
                                done
                            fi
                            if [ -f "$icondir/hicolor/icon-theme.cache" ]; then
                                gtk-update-icon-cache --quiet "$icondir/hicolor" &>/dev/null
                            else
                                gtk-update-icon-cache --quiet --ignore-theme-index "$icondir/hicolor" &>/dev/null
                            fi
                        fi
                        ;;

    esac
    return 0

}


##
# _processTriggers [--session]
# session: process end of session triggers
#
# Process the delayed-command file. If without --session, then commands
# are written to uninstall log file. With --session, then the commands
# are executed.
function _processTriggers() {

    trace called with $1
    local filename_in filename_out exec_text incommand outcommand

    # set filenames based on calling method
    if [[ "$1" == "--session" ]]; then
        filename_in="$WORKING_DIRECTORY/delayed-commands-session"
        filename_out="/dev/null"
    else
        filename_in="$WORKING_DIRECTORY/delayed-commands-package"
        filename_out="$WORKING_DIRECTORY/delayed-commands-session"
    fi

    if [ -e "$filename_in" ]; then

        # when doing log entries reverse order so the commands
        # execute in the proper order in uninstall log
        if [[ "$1" == "--session" ]]; then
            exec_text=`cat "$filename_in" | sort | uniq`
            incommand="_executeTrigger"
        else
            exec_text=`cat "$filename_in" | sort -r | uniq`
            incommand="_logTrigger"
        fi

        echo "$exec_text" | while read; do
            $incommand $REPLY
            # save parameters to session command file
            echo "$REPLY" >> "$filename_out"
        done

    fi

    # remove package command file at the end of the package
    if [ -z "$1" ]; then
        removeFile "$filename_in"
    fi

    return 0

}


##
# _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
# Add mandriva X-MandrivaLinux-* value to category key for their xdg implementation.
function _setupDesktopFile() {
    local adjust_path="$1"
    local F="$2"
    local categories_value category category_add

    if $adjust_path; then
        trace Adjusting path for $F...
        local bindir=$( escapeValue "$PREFIX/bin/" )
        grep -q '^TryExec=/' "$F" || safeSed "$F" "s/^TryExec=/TryExec=$bindir/"
        grep -q '^Exec=/' "$F" || safeSed "$F" "s/^Exec=/Exec=$bindir/"
    fi

    # ensure there is an ending ';' in the 'Categories' values from Desktop Entry section - if not rewrite the entry
    local desktop_entry_section=$( getSection "$F" "Desktop Entry" )
    local cat_count=$( echo "$desktop_entry_section" | grep -c '^Categories' )
    if (( cat_count == 1 )); then
        categories_value=`echo "$desktop_entry_section" | grep '^Categories=' | awk 'BEGIN{FS="="}; { print $2 }' -`
        trace categories_value is $categories_value
        local i=${#categories_value}
        (( i-- ))
        if [[ ${categories_value:$i} != ";" ]]; then
            trace adding ';' to Desktop Entry Categories values in $F
            addSectionLine "$F" "Desktop Entry" "Categories=${categories_value};" "^Categories="
            # reload categories_value
            desktop_entry_section=$( getSection "$F" "Desktop Entry" )
            categories_value=`echo "$desktop_entry_section" | grep '^Categories=' | awk 'BEGIN{FS="="}; { print $2 }' -`
        fi
        if ! echo "$categories_value" | grep -qF "X-Red-Hat-Base;"; then
            trace adding X-Red-Hat-Base to $F...
            addSectionLine "$F" "Desktop Entry" "Categories=${categories_value}X-Red-Hat-Base;" "^Categories="
        fi

        # mandriva category mangling area - compatibility till full implementation of xdg
        if [[ "$AUTOPACKAGE_DISTRIBUTION_ID" == "mandriva" ]]; then

            # add second level category first before adding first level category
            # second level is more specific and only one category X-MandrivaLinux-* is added

            for category in `echo $categories_value | sed 's/\;/ /g'`; do
                case $category in

                    # second level categories
                    Dictionary|Clock ) 				category_add="X-MandrivaLinux-Office-Accessories"; break;;
                    ContactManagement ) 			category_add="X-MandrivaLinux-Office-AddressBooks"; break;;
                    PDA ) 							category_add="X-MandrivaLinux-Office-Communications-PDA"; break;;
                    Telephony ) 					category_add="X-MandrivaLinux-Office-Communications-Phone"; break;;
                    2DGraphics|VectorGraphics|RasterGraphics ) 		category_add="X-MandrivaLinux-Office-Drawing"; break;;
                    Chart|FlowChart ) 				category_add="X-MandrivaLinux-Office-Graphs"; break;;
                    Presentation ) 					category_add="X-MandrivaLinux-Office-Presentations"; break;;
                    Scanning|OCR ) 					category_add="X-MandrivaLinux-Office-Publishing"; break;;
                    Spreadsheet ) 					category_add="X-MandrivaLinux-Office-Spreadsheets"; break;;
                    ProjectManagement ) 			category_add="X-MandrivaLinux-Office-TasksManagement"; break;;
                    Calendar ) 						category_add="X-MandrivaLinux-Office-TimeManagement"; break;;
                    WordProcessor ) 				category_add="X-MandrivaLinux-Office-Wordprocessors"; break;;
                    IRCClient ) 					category_add="X-MandrivaLinux-Internet-Chat"; break;;
                    FileTransfer|P2P ) 				category_add="X-MandrivaLinux-Internet-FileTransfer"; break;;
                    InstantMessaging ) 				category_add="X-MandrivaLinux-Internet-InstantMessaging"; break;;
                    Email ) 						category_add="X-MandrivaLinux-Internet-Mail"; break;;
                    News ) 							category_add="X-MandrivaLinux-Internet-News"; break;;
                    HamRadio ) 						category_add="X-MandrivaLinux-Internet-Other"; break;;
                    RemoteAccess|Dialup ) 			category_add="X-MandrivaLinux-Internet-RemoteAccess"; break;;
                    WebBrowser ) 					category_add="X-MandrivaLinux-Internet-WebBrowsers"; break;;
                    WebDevelopment ) 				category_add="X-MandrivaLinux-Internet-WebEditors"; break;;
                    Photography|3DGraphics|Viewer ) 	category_add="X-MandrivaLinux-Multimedia-Graphics"; break;;
                    Midi|Mixer|Sequencer|Tuner|AudioVideoEditing|Player|Recorder ) 	category_add="X-MandrivaLinux-Multimedia-Sound"; break;;
                    TV ) 							category_add="X-MandrivaLinux-Multimedia-Video"; break;;
                    Archiving ) 					category_add="X-MandrivaLinux-System-Archiving-Backup"; break;;
                    DiscBurning ) 					category_add="X-MandrivaLinux-System-Archiving-CDBurning"; break;;
                    DesktopSettings ) 				category_add="X-MandrivaLinux-System-Configuration"; break;;
                    HardwareSettings ) 				category_add="X-MandrivaLinux-System-Configuration-Hardware"; break;;
                    PackageManager ) 				category_add="X-MandrivaLinux-System-Configuration-Packaging"; break;;
                    Filesystem|FileManager ) 		category_add="X-MandrivaLinux-System-FileTools"; break;;
                    Monitor ) 						category_add="X-MandrivaLinux-System-Monitoring"; break;;
                    TerminalEmulator ) 				category_add="X-MandrivaLinux-System-Terminals"; break;;
                    Accessibility ) 				category_add="X-MandrivaLinux-MoreApplications-Accessibility"; break;;
                    Database ) 						category_add="X-MandrivaLinux-MoreApplications-Databases"; break;;
                    Building ) 						category_add="X-MandrivaLinux-MoreApplications-Development-CodeGenerators"; break;;
                    IDE|GUIDesigner ) 				category_add="X-MandrivaLinux-MoreApplications-Development-DevelopmentEnvironments"; break;;
                    Debugger|Profiling|RevisionControl|Translation ) 	category_add="X-MandrivaLinux-MoreApplications-Development-Tools"; break;;
                    TextEditor ) 					category_add="X-MandrivaLinux-MoreApplications-Editors"; break;;
                    Emulator ) 						category_add="X-MandrivaLinux-MoreApplications-Emulators"; break;;
                    Finance ) 						category_add="X-MandrivaLinux-MoreApplications-Finances"; break;;
                    AdventureGame ) 				category_add="X-MandrivaLinux-MoreApplications-Games-Adventure"; break;;
                    ArcadeGame ) 					category_add="X-MandrivaLinux-MoreApplications-Games-Arcade"; break;;
                    BoardGame ) 					category_add="X-MandrivaLinux-MoreApplications-Games-Boards"; break;;
                    CardGame ) 						category_add="X-MandrivaLinux-MoreApplications-Games-Cards"; break;;
                    ActionGame|KidsGame|RolePlaying|Simulation ) 	category_add="X-MandrivaLinux-MoreApplications-Games-Other"; break;;
                    LogicGame|BlocksGame ) 			category_add="X-MandrivaLinux-MoreApplications-Games-Puzzles"; break;;
                    SportsGame ) 					category_add="X-MandrivaLinux-MoreApplications-Games-Sports"; break;;
                    StrategyGame ) 					category_add="X-MandrivaLinux-MoreApplications-Games-Strategy"; break;;
                    Amusement ) 					category_add="X-MandrivaLinux-MoreApplications-Games-Toys"; break;;
                    Astronomy ) 					category_add="X-MandrivaLinux-MoreApplications-Sciences-Astronomy"; break;;
                    Biology ) 						category_add="X-MandrivaLinux-MoreApplications-Sciences-Biology"; break;;
                    Chemistry ) 					category_add="X-MandrivaLinux-MoreApplications-Sciences-Chemistry"; break;;
                    Electronics ) 					category_add="X-MandrivaLinux-MoreApplications-Sciences-Electricity"; break;;
                    Geology ) 						category_add="X-MandrivaLinux-MoreApplications-Sciences-Geosciences"; break;;
                    Math ) 							category_add="X-MandrivaLinux-MoreApplications-Sciences-Mathematics"; break;;
                    MedicalSoftware|Engineering ) 	category_add="X-MandrivaLinux-MoreApplications-Sciences-Other"; break;;
                    Physics ) 						category_add="X-MandrivaLinux-MoreApplications-Sciences-Physics"; break;;
                    Shell ) 						category_add="X-MandrivaLinux-MoreApplications-Shells"; break;;
                    Education ) 					category_add="X-MandrivaLinux-MoreApplications-Education"; break;;
                    Languages ) 					category_add="X-MandrivaLinux-MoreApplications-Education-Languages"; break;;
                    Science ) 						category_add="X-MandrivaLinux-MoreApplications-Education-Sciences"; break;;
                    Art|Construction|Music|Teaching ) 	category_add="X-MandrivaLinux-MoreApplications-Education-Other"; break;;

                esac
            done

            # check for first level category if second level category is not determined
            if [ -z "$category_add" ]; then
                for category in `echo $categories_value | sed 's/\;/ /g'`; do
                    case $category in

                        # first level categories
                        Audio ) 		category_add="X-MandrivaLinux-Multimedia-Sound"; break;;
                        Video ) 		category_add="X-MandrivaLinux-Multimedia-Video"; break;;
                        #AudioVideo ) 	category_add="X-MandrivaLinux-Multimedia"; break;;
                        Development ) 	category_add="X-MandrivaLinux-MoreApplications-Development"; break;;
                        Education ) 	category_add="X-MandrivaLinux-MoreApplications-Education"; break;;
                        Game ) 			category_add="X-MandrivaLinux-MoreApplications-Games"; break;;
                        Graphics ) 		category_add="X-MandrivaLinux-Multimedia-Graphics"; break;;
                        Network ) 		category_add="X-MandrivaLinux-Internet"; break;;
                        Office ) 		category_add="X-MandrivaLinux-Office"; break;;
                        Settings ) 		category_add="X-MandrivaLinux-System-Configuration"; break;;
                        System ) 		category_add="X-MandrivaLinux-System"; break;;
                        Utility ) 		category_add="X-MandrivaLinux-Office-Accessories"; break;;

                    esac
                done
            fi

            # add default category if not determined by second levels and first levels
            if [ -z "$category_add" ]; then
                 category_add="X-MandrivaLinux-MoreApplications-Other"
            fi

            # add determined category to desktop file
            trace adding mandriva category $category_add
            addSectionLine "$F" "Desktop Entry" "Categories=${category_add};${categories_value}" "^Categories="

        fi

    elif (( cat_count > 1 )); then
        err "installMenuItem: desktop file $F has more than 1 'Categories' keys in the Desktop Entry section."
    fi

    # check if we need to update MIME database
    if grep -q '^MimeType=' "$F"; then
        # register update-mime-database trigger
        _registerTrigger mime
    else
        warn no MimeType line for $F
    fi

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

    # add action menu text to .desktop file and add short name
    #outn "$DESKTOP_ACTION_UPDATE" "$SHORTNAME" >> "$F";
    outn "$DESKTOP_ACTION_VERIFY" "$SHORTNAME" >> "$F";
    outn "$DESKTOP_ACTION_REMOVE" "$SHORTNAME" >> "$F";
    
    if [ `id -u` -eq 0 ]; then
        safeSed "$F" "s|package remove Short_Name|/usr/libexec/autopackage/autosu-gtk --root-only package remove Short_Name|"
    fi
    safeSed "$F" "s/Short_Name/${SHORTNAME}/"

    # 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="
    addSectionLine "$F" "Desktop Entry" "Actions=Apkg-Verify;Apkg-Remove;$action_value" "^Actions="
}


##
# installIcon <SOURCES>
# SOURCES: Icon files or directories to install.
# Returns: 0 on success, 1 on error.
#
# Installs an icon to appropriate directories, so that your desktop is guaranteed to be able to
# locate these icons for display in menus items. This function can be used in combination
# with installMenuItem().
# You should ship and install at least a 48x48 icon in PNG format.
#
# See also: getIconDirs(), freedesktop.org
# <a href="http://freedesktop.org/wiki/Standards/basedir-spec">Base Directory Specification</a>
# and freedesktop.org <a href="http://freedesktop.org/wiki/Standards/icon-theme-spec">Icon Theme
# Specification</a>.
#
# The directory structure of the directory passed as an argument to
# installIcon() should follow the structure specified by the FreeDesktop.org Icon Specification.
# The structure is &lt;theme&gt;/&lt;size&gt;/&lt;type&gt;/&lt;name&gt;. All applications should install an icon for
# the hicolor theme, as it is the theme that all desktop environments use as a fallback default
# (and the standard specified by the FDO icon spec).
# SVG icons can be installed into &lt;theme&gt;/scaleable.
# For example:
# share/icons/hicolor
#      `_ 48x48/apps/yourapp.png
#      `- 16x16/apps/yourapp.png
#      `- scaleable/apps/yourapp.svg
#      `- 48x48/mimetypes/yourdoc.png
#
# Example:
# The application FooBar installs foobar.desktop, which contains this line for the icon:
#   Icon=foobar.png
# The application ships share/icons/hicolor/48x48/apps/foobar.png and wants it to be used as a
# default icon for foobar.desktop, except if the current icon theme provides it's own icon for foobar.
# The following two commands will take care of everything:
#
# installIcon share/icons/hicolor
# installMenuItem CATEGORY foobar.desktop
function installIcon() {
	pushOptE; set +e;
	local F D

	for F in "$@"; do

		# filename should be installed into the same base location as directory
		# but desktop implementations make that impossible at the present moment
		#
		# fixme: with XDG_* variables, directories and filenames should be
		# installed to the same base directory location
		if [ -f "$F" ]; then
			__outputStatus_status="file"
			outputStatus "$intl_INSTALLING_ICON"
		elif [ -d "$F" ]; then
			__outputStatus_status="directory"
			outputStatus "$intl_INSTALLING_ICON_THEME"
		else
			err source \"$F\" was not found.
			popOptE
			return 1
		fi

		# Check if _icondirs was already set by a previous recursion of this loop
		if [ ! "${_icondirs[0]}" ]; then
			declare -a _icondirs
			local oIFS="$IFS"
			IFS=$'\n'
			_icondirs=(`getIconDirs`)
			IFS="$oIFS"
		fi

		for D in "${_icondirs[@]}"; do
			# have no progressBar output as each call in this loop would
			# generate its own progressBar - showing 0 is better than 4
			copyFiles --silent --noprogressbar "$F" "$D"
			# Make sure desktop is notified of new icon
			touch "$D" "$D/.." "$D/../.." "$D/../../.." 2>/dev/null
		done

		# register icon trigger
		_registerTrigger icon "${_icondirs[@]}"

	done

	popOptE
	return 0
}


# ##
# # installSound <SOURCES>
# # SOURCES: Sound files or directories to install.
# # Returns: 0 on success, 1 on error.
# #
# # Install files to proper desktop sound directory.
# #
# # See also: freedesktop.org Base Directory Specification and freedesktop.org Icon Theme Specification.
# #
# # Example:
# # installSound ./share/sounds/exit.ogg
# # #   --> <sound-dir>/$SHORTNAME/exit.ogg
# #
# # Install a theme by defining a source directory:
# # installSound ./share/sounds/theme-name
# # #   --> <sound-dir>/theme-name
#
# # Premise is that sound will be similar to the handling of icons.
# # Implementation represented from XDG Icon Theme Specification   http://freedesktop.org/Standards/icon-theme-spec/
# # Implementation for XDG Base Directory Specification   http://freedesktop.org/Standards/basedir-spec/
# # function installSound() {
# 	pushOptE; set +e;
# 	local F
#
# 	if [ ! "$sounddir" ]; then
# 		if [[ `id -u` != "0" ]]; then
# 			if [[ "$XDG_DATA_HOME" != "" ]]; then
# 				sounddir="$XDG_DATA_HOME/sounds"
# 			else
# 			# Backwards Compatibility
# 				sounddir="$HOME/.sounds"
# 			fi
# 		else
# 			# $PREFIX should be /usr/local/share/ or /usr/share/ if
# 			# $XDG_DATA_DIRS is either not set or empty. Otherwise
# 			# $PREFIX should be one of the directories in $XDG_DATA_DIRS
# 			# for the users so the installation can be found.
# 			sounddir="$PREFIX/share/sounds"
# 		fi
# 	fi
#
# 	for F in "$@"; do
#
# 		if [ -f "$F" ]; then
#
# 			__outputStatus_status="file"
# 			outputStatus "$intl_INSTALLING_SOUND"
# 			copyFiles --silent "$F" "$sounddir/$SHORTNAME"
#
# 		elif [ -d "$F" ]; then
#
# 			__outputStatus_status="directory"
# 			outputStatus "$intl_INSTALLING_SOUND_THEME"
# 			copyFiles --silent "$F" "$sounddir"
#
# 		else
#
# 			err source \"$F\" was not found.
# 			popOptE
# 			return 1
#
# 		fi
#
# 	done
#
# 	popOptE
# 	return 0
# }


##
# getIconDirs
# Outputs: a list of path, seperated by newlines.
#
# Get the paths in which icons are installed to.
#
# See also: installIcon()
function getIconDirs() {

	local output

	if [[ `id -u` == "0" ]]; then

		local gnome2prefix
		local kdeprefix

		if gnome2prefix=`getGnome2Prefix`; then
			output=`echo "$output"; echo "$gnome2prefix/share/pixmaps"`
		fi
		if kdeprefix=`getKdePrefix`; then
			output=`echo "$output"; echo "$kdeprefix/share/icons"`
		fi
		if [[ "$gnome2prefix" == "" && "$kdeprefix" == "" ]]; then
			output=`echo "$output"; echo "/usr/share/pixmaps"`
		fi

		# usr prefix should always be installed for legacy and XDG
		output=`echo "$output"; echo "/usr/share/icons"`
		stripBlankLines "$output" | uniq

	else

		output=`echo "$HOME/.icons/gnome/48x48/apps"; echo "$HOME/.kde/share/icons"; echo "$HOME/.icons"`
		if [ -z "$XDG_DATA_HOME" ]; then
			output=`echo "$output"; echo "$HOME/.local/share/icons"`
		else
			output=`echo "$output"; echo "$XDG_DATA_HOME/icons"`
		fi
		stripBlankLines "$output" | uniq

	fi

	return 0

}


##
# getGnome2Prefix
# Outputs: A directory name, or nothing when GNOME 2 is not found.
# Returns: 0 when found, 1 when not found.
#
# Get the prefix where GNOME 2 is installed to.
function getGnome2Prefix() {
    pushOptE; set +e;
    local gnome2dir
    if locateCommand pkg-config --exists gnome-vfs-2.0; then
        # workaround because pkg-config does not give any error code on package check call or variable output call
        # "$lc_location" --variable=prefix gnome-vfs-2.0
        gnome2dir=`"$lc_location" --variable=prefix gnome-vfs-2.0`
        if [[ "$gnome2dir" != "" ]]; then
            echo "$gnome2dir"
            popOptE; return 0;
        fi
    fi
    if locateCommand gnome-panel; then
        gnome2dir=`dirname "$lc_location"`
        gnome2dir=`dirname "$gnome2dir"`
        echo "$gnome2dir"
        popOptE; return 0;
    else
        trace gnome2 not found
        popOptE; return 1;
    fi
}


##
# installGnome2AppEntry <FILENAMES>
# FILENAMES: The .applications files to install.
#
# Install GNOME 2 application entry files (.applications).
function installGnome2AppEntry() {
    pushOptE; set +e
    outputStatus "$intl_INSTALLING_GNOME2_APP_ENTRY"
    local dir
    if [[ `id -u` == "0" ]]; then
        if dir=`getGnome2Prefix`; then
            dir="$dir/share/application-registry"
        else
            trace gnome2 not found, returning
            popOptE; return 0
        fi
    else
        dir="$HOME/.gnome/application-info"
    fi
    trace dir=$dir
    copyFiles --silent "$@" "$dir"
    popOptE; return 0
}


##
# installGnome2Mime <FILENAMES>
# FILENAMES: The .mime or .keys files to install.
# Returns: 0 on success, 1 on error.
#
# Install GNOME 2 MIME entries (.mime/.keys).
function installGnome2Mime() {
    pushOptE; set +e
    outputStatus "$intl_INSTALLING_GNOME2_MIME"
    local dir
    if [[ `id -u` == "0" ]]; then
        if getGnome2Prefix > /dev/null; then
            dir="`getGnome2Prefix`/share/mime-info"
        else
            popOptE; return 0
        fi
    else
        dir="$HOME/.gnome/mime-info"
    fi
    copyFiles --silent "$@" "$dir"
    popOptE; return 0
}


##
# getKdePrefix
# Outputs: A directory name, or nothing when KDE 2 or 3 are not found.
# Returns: 0 when found, 1 when not found.
#
# Get the PREFIX where KDE 2 or 3 are installed to.
function getKdePrefix() {
    if locateCommand kicker; then
        dirname "`dirname \"$lc_location\"`"
        return 0
    else
        return 1
    fi
}


##
# installKdeMimeApp <FILENAMES>
# FILENAMES: The .desktop files to install.
# Deprecated: 1.2
function installKdeMimeApp() {
    installMimeDesktop $@
}

##
# installKDEMime <FILENAMES>
# FILENAMES: The .desktop files to install.
# Returns: 0 on success, 1 on error.
# Since: 1.2
#
# Install KDE MIME entries (.desktop).
#
# You probably don't need to use this function in your
# specfiles. installMime() automatically calls it
# for you to install the KDE MIME entries that were generated
# from the FreeDesktop.org XML MIME file.
function _installKDEMime() {
    pushOptE; set +e
    outputStatus "$intl_INSTALLING_KDE_MIME"
    trace "got $@ passed to installKDEMime"

    local kdedir
    kdedir=$( getKdePrefix )

    if [[ "$kdedir" != "" ]]; then
        local mimelnkdir

        if ! haveWriteAccess "$kdedir"; then
            if [[ `id -u` == "0" ]]; then #kdedir is unwriteable and we're root--bail out, something is wrong
                popOptE; return 1
            fi

            kdedir="$HOME/.kde"
        fi

        for mimefile in "$@"; do
            trace "mimefile is $mimefile"
            if [ ! -e $mimefile ]; then # this check is necessary because sed is called before copyFiles
                err "File $mimefile does not exist!"
                popOptE; return 1
            fi
            local toplev=`sed -n 's/MimeType=\(.*\)\/.*$/\1/p' $mimefile` # find category (text/ in text/html)
            trace "toplev is $toplev"
            copyFiles --silent "$mimefile" "$kdedir/share/mimelnk/$toplev/"
        done;

        # if kde window manager is running then force reload of desktop files
        # register kbuildsycoca trigger
        _registerTrigger kbuildsycoca

    else
        trace no kde found
    fi

    popOptE; return 0
}

##
# installMimeDesktop --no-adjust-path <DESKTOP-FILES...>
# --no-path-adjust: Do not change paths in the .desktop file to absolute paths.
# DESKTOP-FILES: a list of .desktop files.
#
# Sometimes you want to associate a program with a particular file type, but you
# don't want that program to appear in the menus. This function installs a MIME
# type association .desktop file such that it won't appear in the menus but will
# still be used for file assocations. Remember to use installMime to register your
# MIME type.
#
# By default, this function will change the paths in the TryExec, Exec
# fields to absolute filenames by prepending "$PREFIX/bin".
# For instance, "Exec=gimp" will be changed to "Exec=/home/myuser/.local/bin/gimp".<br>
#
# If you do not want installMimeDesktop to change the paths, pass the --no-path-adjust argument.
function installMimeDesktop() {
        pushOptE; set +e

        local adjust_path=true
        if [[ "$1" == "--no-adjust-path" ]]; then
                adjust_path=false
                shift
        fi

        outputStatus "$intl_INSTALLING_FILE_ASSOCIATIONS"

        local kdedir
        local F

        kdedir=$( getKdePrefix )

        # for kde 2/3.0 and what else?
        if [[ "$kdedir" != "" ]]; then
            local applnkdir

            if ! haveWriteAccess "$kdedir"; then
                # not root
                kdedir="$HOME/.kde"
            fi

            applnkdir="$kdedir/applnk";
            if [ -d "$kdedir/applnk-redhat" ]; then
                applnkdir="$kdedir/applnk-redhat";
            fi

            copyFiles --silent "$@" "$applnkdir/.hidden"
            for F in "$@"; do
                F=`basename "$F"`
                _setupDesktopFile $adjust_path "$applnkdir/.hidden/$F"
            done
        else
            trace no kde found
        fi

        # we don't want them to show in the menus ...
        for F in $@; do
            trace "hiding and doing final setup on $F"
            addSectionLine "$F" "Desktop Entry" "NoDisplay=true" "^NoDisplay="
            _setupDesktopFile $adjust_path "$F"
        done

        # now let's do the standard system (gnome 2.8, possibly kde 3.3)
        copyFiles --silent "$@" "$PREFIX/share/applications"

        # register update-desktop-database trigger
        _registerTrigger desktop

        # if kde window manager is running then force reload of desktop files
        # register kbuildsycoca trigger
        _registerTrigger kbuildsycoca

        popOptE;
        return 0
}


##
# installMime <FILENAMES>
# FILENAMES: xml Mime file(s) to install.
#
# Install mime-info xml files into appropriate directory and runs update-mime-database.
# This will automatically install any KDE .desktop files that were automatically generated.
#
# Implementation is for the XDG Shared MIME Database Specification   http://freedesktop.org/wiki/Standards_2fshared_2dmime_2dinfo_2dspec
#
# Example:
# installMime share/mime/packages/foobar.xml
function installMime() {

    pushOptE; set +e;

    outputStatus "$intl_INSTALLING_MIME"
    trace called with $@

    # Initialize Base Desktop Directories
    if ! ${__installMenuItem_initialized:-false}; then
        _installMenuItemInitialize
    fi
    
    local xdgDefsToCopy
    local kdeDefsToCopy
    
    for i in $@; do
        # check each file that was passed to installMime and make sure it wasn't
        # created by generageLegacyMime (ends in a number and is a symlink).
        # This allows you to use installMime share/mime/packages/*
        if [[ `echo $i | grep -c \.[0-9]$` = "1" && -L "$i" ]]; then
            trace "$i is a KDE symlink, installing later"
        else
            trace "installing $i as XDG"
            xdgDefsToCopy="$xdgDefsToCopy $i"
        fi
    done

    copyFiles --silent $xdgDefsToCopy "$xdgdir_mime/packages"

    # register update-mime-database trigger
    _registerTrigger mime

    trace done installing XML files, now doing KDE
    for i in $xdgDefsToCopy; do
        for mimelnkfile in `ls $i\.[0-9] 2> /dev/null`; do
            trace "got $mimelnkfile as KDE link"
            # use `readlink` to get the "real" filename for proper name when file is installed
            kdeDefsToCopy="$kdeDefsToCopy `dirname $mimelnkfile`/`readlink $mimelnkfile`"
        done
    done
    trace "installing $kdeDefsToCopy as KDE"
    _installKDEMime $kdeDefsToCopy
    trace "finished installing KDE, all done now"

    popOptE
    return 0
}


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


##
# removeDir <DIRECTORY>
# DIRECTORY: The directory to remove.
# Returns: 0 always.
#
# Recursively check if DIRECTORY is empty, and remove it if it is.
# Checks for any directory in the DIRECTORYs path.
#
# See also: dirIsEmpty()
#
# Example:
# mkdir -p a/deep/directory
# touch a/file
# pruneDir a/deep/directory
# ls a/deep   # =>  "a/deep: no such file or directory"
# ls a/file   # =>  exists
function removeDir() {
    trace called with $@
    local location="$1"

    # find the first existing directory
    while [ ! -d "$location" ]; do
        trace does not exist $location
        location=`dirname "$location"`
        if [[ "$location" == "/" ]]; then
            return 0
        fi
    done

    pushd "$location" >/dev/null
    while dirIsEmpty . --no-recurse; do
        local a=`basename "$(pwd)"`
        cd ..
        rmdir "$a"
        trace removed `pwd`/$a
    done
    popd >/dev/null
    return 0
}


# called from an uninstall script to eliminate a linker cache entry
function removeLinkerCacheEntry() {
    local files=$(ls "$1"/*.so "$1"/*.so.* 2>/dev/null)
    if [ -z "$files" ]; then
        trace $1 empty, removing from ld.so.conf
        local entry=`escapeValue "$1"`
        safeSed /etc/ld.so.conf "/^$entry$/d"
        # register ldconfig trigger
        _registerTrigger ldconfig
    fi
    return 0
}

# $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 removeInfo() {
    # ARGH!!! install-info is junk, so manually edit the dir file to avoid things being screwed up
    # Check for Info directory and Info file location
    info_dir_location=/usr/info/dir
    [ -e /usr/share/info/dir ] && info_dir_location=/usr/share/info/dir
    f=`echo "$1" | sed 's/\.info.gz//'`
    # if root has not previously installed an info file from a package
    if [[ `id -u` == "0" ]]; then
        # this grep fails for a user because it does not exist yet :: FIXME
        # just protected from user with a id check above- C.
        [ -e "$info_dir_location" ] && 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=`sed "${l}d" <"$info_dir_location"`
            echo "$temp_buffer" > "$info_dir_location"
        fi
    fi
}

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

##
# _findGlibcVersions <DIRECTORY>
# DIRECTORY: 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 LC_ALL=C file "$REPLY" | LC_ALL=C grep -q ELF; then
		objdump -p "$REPLY" | LC_ALL=C 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() {
    if isLibrary32 /lib/libc.so.6; then
        dumpverdefs32 /lib/libc.so.6 $@
    else
        dumpverdefs64 /lib/libc.so.6 $@
    fi
}

##
# getPythonLibDir
# Outputs: A directory path.
# Returns: 0 on success, non-zero on failure (for example, if Python is not installed).
#
# Outputs the directory where Python modules should be stored.
#
# Example:
# getPythonLibDir   # => /usr/lib/python2.2/site-packages
function getPythonLibDir() {
    python -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib()" 2>/dev/null
    return $?
}

##
# testForPythonModule <MODULE>
# MODULE: The module to test for
# Returns: 0 when module is found, non-zero on failure (Module/Python is not installed)
#
# Tests if the Python module MODULE is available by running `python -c "import MODULE"`
#
function testForPythonModule() {
    pushOptE; set +e;
    if locateCommand python; then
	trace python found, testing
        local r
	python -c "import $1" 2>/dev/null;
        r=$?
        popOptE; return $r
    else
	warn python not found, failing
	return 1
    fi
}

##
# logFile <FILENAME>
# FILENAME: filename that will be logged.
#
# Add FILENAME to the uninstall file log. This file will be
# automatically removed during uninstallation.
function logFile() {
	echo "$1" >> "$apkg_filelist"
	local logfile_dir=`dirname "$1"`
	logCommand --session "removeFile `escapeFilename \"$1\"`"
	logCommand --session "removeDir `escapeFilename \"$logfile_dir\"`"
}

##
# logDir <DIRECTORY>
# DIRECTORY: directory that will be logged.
#
# Add DIRECTORY to the uninstall directory log. This directory will be
# automatically removed during uninstallation, if it's empty.
function logDir() {
	echo "$1" >> "$apkg_uninstalldirs"
	logCommand --session "removeDir `escapeFilename \"$1\"`"
}

##
# logCommand --session <MESSAGE>
# --session: log only to session file.
# MESSAGE: string that will be logged.
#
# Add MESSAGE to the log. MESSAGE will be executed during uninstallation.
function logCommand() {

	# allow for temporary state to be captured
	# and not write to any other logging files
	if [ "$1" == "--session" ]; then
	    shift
	    echo "$@" >> "$_autopackage_session"
	    return
	else
	    echo "$@" >> "$_autopackage_session"
	    echo "$@" >> "$apkg_logfile"
	    return
	fi

}

##
# createBootstrapScript <BINARY> <FILENAME> [ADDITIONAL-COMMANDS]
# BINARY: the filename of an application.
# FILENAME: the filename to which the bootstrap script is written.
# Returns: 0 on success, 1 on error.
#
# Create a bootstrap script for BINARY. A bootstrap script is a script
# which sets up various environment variables (such as $PATH, $LD_LIBRARY_PATH, etc.),
# then run BINARY. That way it ensures BINARY can actually be run.
#
# If ADDITIONAL-COMMANDS is given, it will be included in the bootstrap script. The
# commands in this option will be run just before BINARY is started.
#
# FILENAME will be added to the uninstall log.
function createBootstrapScript() {
	local binary="$1"
	local filename="$2"
	local commands="$3"

	if [[ "$binary" == "" || "$filename" == "" ]]; then
		err "Usage: createBootstrapScript <BINARY> <FILENAME>"
		return 1
	fi

	local dir=`dirname "$filename"`
	if [[ ! -d "$dir" ]]; then
		#mkdirs "$dir" || return 1
		return 1
	fi

	cat <<EOF >"$filename"
#!/bin/bash
# Autopackage bootstrap script
# Name:    $SHORTNAME
# Package: $ROOTNAME
# Version: $SOFTWAREVERSION
# $DISPLAYNAME

export PATH="$PREFIX/bin:\$PATH"
export LD_LIBRARY_PATH="$PREFIX/lib:\$LD_LIBRARY_PATH"
$commands

exec "$binary" "\$@"
EOF
	[[ "$?" != "0" ]] && return 1

	chmod +x "$filename"
	logFile "$filename"
	return $?
}


##
# installGConfSchema <FILENAMES>
# FILENAMES: Location of GCONF schema files.
#
# Installs given schema FILENAMES to the GConf database.
#
# Example:
# installGConfSchema "foobar.schemas"
function installGConfSchema() {

	pushOptE; set +e;
	local F

	outputStatus "$intl_INSTALLING_GCONF_SCHEMA"
	trace called with $@

	if [[ "$#" != "1" ]]; then
		err must have one argument: FILENAME
		return 1;
	fi

	# User:
	# GCONF_CONFIG_SOURCE= gconftool-2 --makefile-install-rule libgnomesu.schemas
	# Root:
	# GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source` gconftool-2 --makefile-install-rule libgnomesu.schemas

	if locateCommand gconftool-2 || locateCommand gconftool-1; then

		if [[ "$GCONF_CONFIG_SOURCE" == "" ]]; then
			export GCONF_CONFIG_SOURCE=`"$lc_location" --get-default-source`
		fi

		# copy file to Gconf base directory, install, and log
		etc_dir=`_userConfig`
		if [[ `id -u` == "0" ]]; then
			copyFiles --silent --nolog --nobackup "$@" "$etc_dir/gconf/schemas"
			for F in "$@"; do
				F=`basename "$F"`
				"$lc_location" --makefile-install-rule "$etc_dir/gconf/schemas/$F" > /dev/null
				logCommand "removeGConfSchema `escapeFilename \"$etc_dir/gconf/schemas/$F\"`"
			done

		# install-schema-file does not work and makefile-install-rule requires write access
		# to /etc. GConf does not seem to pick up user installed schemas. -C

		else

			# gconf goes not use XDG user config directory specification
			# probe for user defined gconf directory
			local user_schema_dir
			if [ -f "/etc/gconf/2/path" ]; then
				user_schema_dir="`grep readwrite </etc/gconf/2/path | sed 's/xml:readwrite://; s|(|{|; s|)|}|'`/schemas"
			elif [ -f "/etc/gconf/1/path" ]; then
				user_schema_dir="`grep readwrite </etc/gconf/1/path | sed 's/xml:readwrite://; s|(|{|; s|)|}|'`/schemas"
			fi
			user_schema_dir=`eval echo $user_schema_dir`
			trace located gconf user schema directory: $user_schema_dir
			if [[ "$user_schema_dir" != "" ]]; then
				copyFiles --silent --nolog --nobackup "$@" "$user_schema_dir"
				for F in "$@"; do
					F=`basename "$F"`
					"$lc_location" --install-schema-file="$user_schema_dir/$F" > /dev/null
					logCommand "removeGConfSchema `escapeFilename \"$user_schema_dir/$F\"`"
				done
			else
				warn user gconf schema directory was not determined and schema was not installed.
			fi

		fi

	fi

	popOptE
	return 0

}


##
# removeGConfSchema <FILENAME>
# FILENAME: Absolute location of GCONF schema file.
#
# Removes given schema FILENAME from the GConf database.
#
# Example:
# removeGConfSchema /home/user/.gconf/schemas/foobar.schema
function removeGConfSchema() {

	trace called with $1
	local schema="$1"

	if [ ! -f "$schema" ]; then
		warn GConf schema file does not exist: $schema
		return 1
	fi

	pushOptE; set +e;

	local basekey=`grep -e '<key>.*</key>' < "$schema" | awk 'BEGIN { FS="<key>" } { print $2 }' \
		| awk 'BEGIN { FS="</key>" } { print $1 }' | awk 'BEGIN { FS="/" } { print "/" $3 "/" $4 }' | uniq`

	if [[ "$basekey" == "" ]]; then
		warn BASEKEY should not be empty
	fi

	trace basekey=$basekey

	if locateCommand gconftool-2 || locateCommand gconftool-1; then

		if [[ "$GCONF_CONFIG_SOURCE" == "" ]]; then
			export GCONF_CONFIG_SOURCE=`"$lc_location" --get-default-source`
		fi

		if [[ `id -u` == "0" ]]; then
			"$lc_location" --makefile-uninstall-rule "$schema" > /dev/null
		else
			# unset all keys relating to schema
			"$lc_location" --unapply-schema "$basekey"
		fi
		removeFile "$schema"
		removeDir `dirname "$schema"`

	fi

	popOptE
	return 0

}


##
# installData <DIRECTORIES>
# DIRECTORIES: data directories to install.
# Returns: 1 for failure and 0 for pass.
#
# Copy DIRECTORIES to the standard data directory ($PREFIX/share),
# while displaying a nice localized "Installing data files..."
# message while copying.
#
# Example:
# # The folder foobar contains:
# # hello.c blabla.png
#
# installData foobar
# # Copies 'foobar' to '$prefix/share/foobar'.
# #
# # Creates:
# # $prefix/share/foobar/hello.c
# # $prefix/share/foobar/blabla.png
function installData() {

    trace called with $@
    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_DATA"

    copyFiles --silent "$@" "$PREFIX/share"
    trace done

    popOptE
    return 0
}


##
# installLocale <DIRECTORY>
# DIRECTORY: locale directory to install.
# Returns: 1 for failure and 0 for pass.
#
# Install locale directory into standard locale directory location.
#
# Example:
# installLocale share/locale
# # --> installs to $PREFIX/share/locale
function installLocale() {

    trace called with $@
    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_LOCALE"

    copyFiles --silent "$@" "$PREFIX/share"

    trace done

    popOptE
    return 0

}

##
# installPkgConfig <FILENAMES>
# FILENAMES: pkgconfig files to install
# Returns: 1 for failure and 0 for pass.
# Since: 1.2
#
# Install pkgconfig files, updates prefix in file, and
# adds path to PKG_CONFIG_PATH if necessary
#
# Example:
# installPkgConfig lib/pkgconfig/*
# # --> installs files to $PREFIX/lib/pkgconfig/
function installPkgConfig() {

    trace called with $@
    if [[ "$PREFIX" == "" ]]; then err "PREFIX must be set for this function"; return 1; fi

    pushOptE; set +e;
    outputStatus "$intl_INSTALLING_PKGCONFIG"

    for pkgfile in "$@"; do
        safeSed "$pkgfile" "s|^prefix=\(.*\)|prefix=$PREFIX|g"
    done

    copyFiles --silent "$@" "$PREFIX/lib/pkgconfig"

    updateEnv --append PKG_CONFIG_PATH "$PREFIX/lib/pkgconfig"

    trace done

    popOptE
    return 0

}

##
# checksym <LIBRARY> <SYMBOL>
# LIBRARY: soname of the library you wish to check, eg libcups.so.2
# SYMBOL: name of the exported symbol you wish to check for
# Since: 1.2
#
# Checks if the named symbol is exported by the library. Simply uses
# dlopen and dlsym to find this out. Useful for checking if certain
# features are available in a given library to determine version data
# in skeletons.
#
# Example:
# if checksym libcups.so.2 cupsDoFileRequest2; then
#     echo CUPS provides that symbol on this system
# fi

###### checksym is actually a native binary ######

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