commit:     9caeb57e67c48376fbd7d8121ae4d3a9e1888b35
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Thu Jun 27 15:15:51 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Fri Jun 28 17:39:01 2024 +0000
URL:        
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=9caeb57e

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 <AT> plushkava.net>

 functions.sh   | 41 +++++++++++++++++++++++++++++++++++++++++
 test-functions | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/functions.sh b/functions.sh
index 798c6c7..43a21e4 100644
--- a/functions.sh
+++ b/functions.sh
@@ -438,6 +438,47 @@ srandom()
        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

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
 

Reply via email to