-# $Id$
-#
# Path information is stored on separate lines in XXXdirs.
-# We extract each directory exists and add it to the appropriate PATH.
+# We check each directory exists and add it to the appropriate PATH.
+# Prepend paths with XXXdirs.pre. They are guaranteed to precede other paths.
+# Append paths with XXXdirs.post. They are not guaranteed to follow others.
+# Set per-OS files in $SYSTEM[/$ARCHITECTURE] subdirectories of $DIR.
#
# Location of the XXXdirs files.
-DIR=$HOME/.profile.d
+DIR=${PROFILE_HOME:-~}/.PATH
+
+# Paths to set and the file to get them from @variable to copy from.
+PATHS="
+PATH:bindirs
+C_INCLUDE_PATH:incdirs
+CPLUS_INCLUDE_PATH:@C_INCLUDE_PATH
+LD_LIBRARY_PATH:libdirs
+MANPATH:mandirs
+PKG_CONFIG_PATH:pkgdirs
+"
+
+function sanitisepath() {
+ local paths="${@//:/ }"
+ local sane
+
+ for path in $paths; do
+ paths="${paths## }"
+ paths="${paths%% }"
+ paths="${paths#$path} "
+ if [ "${sane/:$path:/}" = "$sane" ]; then
+ sane="$sane:$path:"
+ fi
+ done
+
+ sane="${sane//::/:}"
+ sane="${sane#:}"
+ sane="${sane%:}"
+
+ echo "$sane"
+}
# Set one path to be the same as another.
function copypath() {
- newpath="$1"; shift
- oldpath="$1"; shift
+ local newpath="$1"; shift
+ local oldpath="$1"; shift
# Sanitise and export.
- path="$(eval echo \$$oldpath)"
- [ -z "$path" ] || eval export $newpath="$path"
+ local path="$(eval echo \$$oldpath)"
+ [ -z "$path" ] || eval "export $newpath='$path'"
+}
+
+# Try to expand variables in a path definition, discarding it if expansion fails.
+function expandpath() {
+ local path="$1"; shift
+
+ while [ -n "$path" ]; do
+ [ "${path/\$/}" = "$path" ] && return 0
+ path="${path#*\$}"
+
+ local var="${path%%/*}"
+ eval "[ -n \"\$$var\" ] || return 1"
+ done
+
+ return 0
+}
+
+# Helper.
+function addpath() {
+ local path="$1"; shift
+ local dir="$1"; shift
- unset path newpath oldpath
+ if ! expandpath "$dir"; then
+ echo "$path"
+ else
+ dir=$(eval echo "$dir")
+ if [ -d "$dir" ]; then
+ echo "$path:$dir"
+ else
+ echo "$path"
+ fi
+ fi
}
# Set a path from directories.
function makepath() {
- newpath="$1"; shift
- dirs="$1"; shift
-
- # Check the file exists.
- [ -e "$DIR/$dirs" ] || return
+ local newpath="$1"; shift
+ local dirs="$1"; shift
+ # Set IFS to newline only so that we can read $(embedded shell commands).
+ local JGD=$IFS
+ IFS='
+'
# Read them.
- path=
- for dir in $(cat "$DIR/$dirs"); do
- [ -d "$dir" ] || continue
+ local path=
+ while read dir; do
+ path=$(addpath "$path" "$dir")
+ if [ -n "$PROFILE_HOME" -a ! "${dir#\$HOME}" = "$dir" ]; then
+ dir="$PROFILE_HOME${dir#\$HOME}"
+ path=$(addpath "$path" "$dir")
+ fi
+ done < "$dirs"
- path="$path:$dir"
- done
- unset dir
+ # Restore IFS.
+ IFS=$JGD
+
+ # Are we setting, prepending or appending?
+ local existing="$(eval echo \$$newpath)"
+ dirs="${dirs##*/}"
+ local where="${dirs##*.}"
+ case "$where" in
+ "$dirs") ;;
+ pre) path="$path:$existing";;
+ post) path="$existing:$path";;
+ *) return;;
+ esac
# Sanitise path.
- path=${path#:}
+ path=$(sanitisepath "$path")
[ -z "$path" ] && return
# Export.
- eval export $newpath="$path"
+ eval "export $newpath='$path'"
+}
+
+# Remove entries which are symlinks to other existing entries.
+function canonicalisepath() {
+ local path="$1"; shift
+ local newpath=
- unset path newpath dirs
+ local JGD=$IFS
+ IFS='
+'
+
+ local dirs=$(eval echo "\$$path")
+ local check=":$dirs:"
+ for dir in ${dirs//:/
+}; do
+ if [ -L "$dir" ]; then
+ # Is this a symlink to another entry?
+ local canon=$(readlink -f "$dir" 2>/dev/null)
+ if [ -n "$canon" ]; then
+ [ "${check/:$canon:/}" = "$check" ] || continue
+ fi
+ fi
+
+ newpath="$newpath:$dir"
+ done
+
+ IFS=$JGD
+
+ eval "export $path='${newpath##:}'"
}
-makepath PATH bindirs
-makepath C_INCLUDE_PATH incdirs
-copypath CPLUS_INCLUDE_PATH C_INCLUDE_PATH
-makepath LD_LIBRARY_PATH libdirs
-copypath LD_RUN_PATH LD_LIBRARY_PATH
-makepath MANPATH mandirs
-makepath PKG_CONFIG_PATH pkgdirs
+# Construct directory list, omitting nonexistent and undefined ones.
+dirs=
+for dir in "${SYSTEM:-@}/${ARCHITECTURE:-@}" "${SYSTEM:-@}" ""; do
+ [ "${dir/@/}" = "$dir" ] || continue
+ [ -d "$DIR/$dir" ] || continue
+ dirs="$dirs,$DIR/$dir"
+ dirs="${dirs%%/}"
+done
+dirs="${dirs##,}"
+[ "${dirs/,/}" = "$dirs" ] || dirs="{$dirs}"
+
+for path in $PATHS; do
+ var="${path%:*}"
+ source="${path#*:}"
+
+ if [ "${source#@}" = "$source" ]; then
+ for dir in $(eval echo $dirs/$source{,.pre,.post}); do
+ [ -e "$dir" ] || continue
+ makepath "$var" "$dir"
+ done
+ canonicalisepath "$var"
+ else
+ copypath "$var" "${source#@}"
+ fi
+done
-unset dirs copypath makepath newpath
+unset DIR PATHS dir dirs path var source expandpath sanitisepath copypath makepath newpath addpath canonicalisepath