summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKerin Millar <kfm@plushkava.net>2024-06-27 16:15:51 +0100
committerKerin Millar <kfm@plushkava.net>2024-06-28 18:39:01 +0100
commit9caeb57e67c48376fbd7d8121ae4d3a9e1888b35 (patch)
tree20ba2798a3975c7eb3cc50d1bf1b2328f4cc40c0
parentAdd an experimental module for staging new ideas (diff)
downloadgentoo-functions-9caeb57e67c48376fbd7d8121ae4d3a9e1888b35.tar.gz
gentoo-functions-9caeb57e67c48376fbd7d8121ae4d3a9e1888b35.tar.bz2
gentoo-functions-9caeb57e67c48376fbd7d8121ae4d3a9e1888b35.zip
Add the substr() function
POSIX sh does not support substring expansion so it may come in handy. The implementation is based on the awk function of the same name. Signed-off-by: Kerin Millar <kfm@plushkava.net>
-rw-r--r--functions.sh41
-rwxr-xr-xtest-functions39
2 files changed, 80 insertions, 0 deletions
diff --git a/functions.sh b/functions.sh
index 798c6c7..43a21e4 100644
--- a/functions.sh
+++ b/functions.sh
@@ -439,6 +439,47 @@ srandom()
}
#
+# Takes the first parameter as a string (s), the second parameter as a numerical
+# position (m) and, optionally, the third parameter as a numerical length (n).
+# It shall then print a <newline> terminated substring of s that is at most, n
+# characters in length and which begins at position m, numbering from 1. If n is
+# omitted, or if n specifies more characters than are left in the string, the
+# length of the substring shall be limited by the length of s. The function
+# shall return 0 provided that none of the parameters are invalid.
+#
+substr()
+{
+ local i str
+
+ if [ "$#" -lt 2 ]; then
+ warn "substr: too few arguments (got $#, expected at least 2)"
+ return 1
+ elif ! is_int "$2"; then
+ _warn_for_args substr "$2"
+ return 1
+ elif [ "$#" -ge 3 ]; then
+ if ! is_int "$3"; then
+ _warn_for_args substr "$3"
+ return 1
+ elif [ "$3" -lt 0 ]; then
+ set -- "$1" "$2" 0
+ fi
+ fi
+ str=$1
+ i=0
+ while [ "$(( i += 1 ))" -lt "$2" ]; do
+ str=${str#?}
+ done
+ i=0
+ while [ "${#str}" -gt "${3-${#str}}" ]; do
+ str=${str%?}
+ done
+ if [ "${#str}" -gt 0 ]; then
+ printf '%s\n' "${str}"
+ fi
+}
+
+#
# Trims leading and trailing whitespace from one or more lines. If at least one
# parameter is provided, each positional parameter shall be considered as a line
# to be processed. Otherwise, the lines to be processed shall be read from the
diff --git a/test-functions b/test-functions
index 13be61c..736836b 100755
--- a/test-functions
+++ b/test-functions
@@ -664,6 +664,44 @@ test_trueof_any() {
iterate_tests 7 "$@"
}
+test_substr() {
+ set -- \
+ ge 1 - foobar N/A N/A \
+ ge 1 - foobar '' N/A \
+ ge 1 - foobar x N/A \
+ ge 1 - foobar '' '' \
+ ge 1 - foobar x y \
+ eq 0 foobar foobar 1 N/A \
+ eq 0 foobar foobar -1 N/A \
+ eq 0 foobar foobar 1 7 \
+ eq 0 foobar foobar -1 7 \
+ eq 0 foo foobar 1 3 \
+ eq 0 foo foobar -1 3 \
+ eq 0 f foobar 1 1 \
+ eq 0 f foobar -1 1 \
+ eq 0 '' foobar 1 0 \
+ eq 0 '' foobar 1 -1 \
+ eq 0 '' foobar 0 0 \
+ eq 0 '' foobar 0 -1 \
+ eq 0 '' foobar -1 0 \
+ eq 0 '' foobar -1 -1 \
+ eq 0 bar foobar 4 N/A \
+ eq 0 bar foobar 4 4 \
+ eq 0 b foobar 4 1 \
+ eq 0 '' foobar 4 0 \
+ eq 0 '' foobar 4 -1
+
+ callback() {
+ shift
+ expected=$1
+ shift
+ test_description="substr $(quote_args "$@")"
+ str=$(substr "$@") && test "${str}" = "${expected}"
+ }
+
+ iterate_tests 6 "$@"
+}
+
iterate_tests() {
slice_width=$1
shift
@@ -738,6 +776,7 @@ test_is_anyof || rc=1
test_is_subset || rc=1
test_trueof_all || rc=1
test_trueof_any || rc=1
+test_substr || rc=1
cleanup_tmpdir