summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKerin Millar <kfm@plushkava.net>2024-06-03 11:58:44 +0100
committerKerin Millar <kfm@plushkava.net>2024-06-12 08:06:42 +0100
commitd6b03b9ae75d0e76a2620e227cf24d9bcdb5e321 (patch)
tree9d95260a0e089259b9944a36b532dbb6ca37dd27
parentAdd the hr() function to print a horizontal rule (diff)
downloadgentoo-functions-d6b03b9ae75d0e76a2620e227cf24d9bcdb5e321.tar.gz
gentoo-functions-d6b03b9ae75d0e76a2620e227cf24d9bcdb5e321.tar.bz2
gentoo-functions-d6b03b9ae75d0e76a2620e227cf24d9bcdb5e321.zip
Add the whenceforth() function as a type -P alternative
It acts much as type -P does in bash. I would have liked to name it whence but ksh and zsh already have builtins by that name. Signed-off-by: Kerin Millar <kfm@plushkava.net>
-rw-r--r--functions.sh48
-rwxr-xr-xtest-functions39
2 files changed, 85 insertions, 2 deletions
diff --git a/functions.sh b/functions.sh
index c077290..504ee9e 100644
--- a/functions.sh
+++ b/functions.sh
@@ -566,6 +566,51 @@ warn()
}
#
+# Considers the first parameter as the potential name of an executable regular
+# file before attempting to locate it. If not specifed as an absolute pathname,
+# a PATH search shall be performed in accordance with the Environment Variables
+# section of the Base Definitions. If an executable is found, its path shall be
+# printed. Otherwise, the return value shall be 1. This function is intended as
+# an alternative to type -P in bash. That is, it is useful for determining the
+# existence and location of an external utility without potentially matching
+# against aliases, builtins and functions (as command -v can).
+#
+whenceforth()
+(
+ local bin path prefix
+
+ case $1 in
+ /*)
+ # Absolute command paths must be directly checked.
+ [ -f "$1" ] && [ -x "$1" ] && bin=$1
+ ;;
+ *)
+ # Relative command paths must be searched for in PATH.
+ # https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
+ case ${PATH} in
+ ''|*:)
+ path=${PATH}:
+ ;;
+ *)
+ path=${PATH}
+ esac
+ IFS=:
+ set -f
+ for prefix in ${path}; do
+ case ${prefix} in
+ */)
+ bin=${prefix}$1
+ ;;
+ *)
+ bin=${prefix:-.}/$1
+ esac
+ [ -f "${bin}" ] && [ -x "${bin}" ] && break
+ done
+ esac \
+ && printf '%s\n' "${bin}"
+)
+
+#
# Determines whether the first parameter is truthy. The values taken to be true
# are "yes", "true", "on" and "1", whereas their opposites are taken to be
# false. The empty string is also taken to be false. All pattern matching is
@@ -876,8 +921,7 @@ fi
# Store the path to the true binary. It is potentially used by _update_columns.
if [ "${BASH}" ]; then
- # shellcheck disable=3045
- genfun_bin_true=$(type -P true)
+ genfun_bin_true=$(whenceforth true)
fi
# Store the name of the GNU find binary. Some platforms may have it as "gfind".
diff --git a/test-functions b/test-functions
index d90462e..813d524 100755
--- a/test-functions
+++ b/test-functions
@@ -507,6 +507,44 @@ test_hr() {
iterate_tests 5 "$@"
}
+test_whenceforth() {
+ set -- \
+ ge 1 PATH N/A \
+ ge 1 PATH . \
+ ge 1 PATH rather-unlikely-to-exist \
+ ge 1 PATH /var/empty \
+ ge 1 PATH /var/empty/nofile \
+ eq 0 PATH /bin/sh \
+ eq 0 PATH sh \
+ eq 0 '' newer/file \
+ eq 0 . newer/file \
+ eq 0 :/var/empty/x newer/file \
+ eq 0 /var/empty/x: newer/file \
+ eq 0 /var/empty/x::/var/empty/y newer/file \
+ ge 1 '' older/file \
+ ge 1 . older/file \
+ ge 1 :/var/empty/x older/file \
+ ge 1 /var/empty/x: older/file \
+ ge 1 /var/empty/x::/var/empty/y older/file
+
+ chmod +x newer/file
+
+ callback() {
+ shift
+ path=$1
+ shift
+ test_description="whenceforth $(_print_args "$@")"
+ if [ "${path}" = PATH ]; then
+ whenceforth "$@" >/dev/null
+ else
+ PATH=${path} whenceforth "$@" >/dev/null
+ fi
+ }
+
+ iterate_tests 4 "$@"
+}
+
+
iterate_tests() {
slice_width=$1
shift
@@ -571,6 +609,7 @@ test_srandom || rc=1
test_newest || rc=1
test_trim || rc=1
test_hr || rc=1
+test_whenceforth || rc=1
cleanup_tmpdir