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