commit:     8ac82c7c7923954765b994de841f82ec2d5456b7
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Sun Jul  7 23:16:44 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Jul  7 23:38:27 2024 +0000
URL:        
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=8ac82c7c

Correct the implementation of contains_all()

It was not translating IFS to FS correctly. Have it do so and extend the
test suite accordingly.

Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>

 functions.sh   |  36 +++++++++++++----
 test-functions | 126 ++++++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 122 insertions(+), 40 deletions(-)

diff --git a/functions.sh b/functions.sh
index cfaddc3..ccd0d1d 100644
--- a/functions.sh
+++ b/functions.sh
@@ -61,21 +61,41 @@ chdir()
 #
 contains_all()
 {
-       [ "$#" -ge 2 ] && IFS=${IFS} awk -f - -- "$@" <<-'EOF'
+       # shellcheck disable=2097,2098
+       [ "$#" -ge 2 ] &&
+       IFS=${IFS} awk -v ifs_set=${IFS+1} -f - -- "$@" <<-'EOF'
        BEGIN {
-               ifs = ENVIRON["IFS"]
                haystack = ARGV[1]
                argc = ARGC
                ARGC = 1
+               if (ifs_set) {
+                       ifs = ENVIRON["IFS"]
+               } else {
+                       ifs = " \t\n"
+               }
+               # Translate IFS to FS, in accordance with section 2.6.5.
                if (length(ifs) == 0) {
                        FS = "^"
-               } else if (length(ifs) != 3 || ifs ~ /[^ \t\n]/) {
-                       # Split by the first character of IFS.
-                       FS = "[" substr(ifs, 1, 1) "]"
                } else {
-                       # Mimic default field splitting behaviour, per section 
2.6.5.
-                       FS = "[ \t\n]+"
-                       sub("^" FS, "", haystack)
+                       whitespace = ""
+                       FS = "("
+                       for (i = 1; i <= length(ifs); i++) {
+                               char = substr(ifs, i, 1)
+                               if (seen[char]++) {
+                                       continue
+                               } else if (char ~ /[ \t\n]/) {
+                                       whitespace = whitespace char
+                                       FS = FS "[" char "]+|"
+                               } else {
+                                       FS = FS "[" char "]|"
+                               }
+                       }
+                       sub(/\|$/, "", FS)
+                       FS = FS ")"
+               }
+               # Leading whitespace characters must be removed.
+               if (length(whitespace) > 0) {
+                       sub("^[" whitespace "]+", "", haystack)
                }
                # In sh, fields are terminated, not separated.
                sub(FS "$", "", haystack)

diff --git a/test-functions b/test-functions
index 59c0b29..dab0aea 100755
--- a/test-functions
+++ b/test-functions
@@ -721,43 +721,105 @@ test_substr() {
 
 test_contains_all() {
        set -- \
-               ge  1  N/A         N/A         N/A         N/A  \
-               ge  1  'foo  bar'  ''          N/A         N/A  \
-               ge  1  'foo  bar'  ''          ' '         N/A  \
-               ge  1  'foo  bar'  ''          ' bar'      N/A  \
-               ge  1  'foo  bar'  ''          ' bar'      N/A  \
-               ge  1  'foo  bar'  ''          'foo '      N/A  \
-               ge  1  'foo  bar'  ''          'foo  bar'  N/A  \
-               ge  1  'foo  bar'  ' '         ''          N/A  \
-               ge  1  'foo  bar'  ' '         ' '         N/A  \
-               ge  1  'foo  bar'  ' '         N/A         N/A  \
-               ge  1  'foo  bar'  ' bar'      ''          N/A  \
-               ge  1  'foo  bar'  ' bar'      N/A         N/A  \
-               ge  1  'foo  bar'  'foo '      ''          N/A  \
-               ge  1  'foo  bar'  'foo '      ' bar'      N/A  \
-               ge  1  'foo  bar'  'foo '      N/A         N/A  \
-               ge  1  'foo  bar'  'foo  bar'  ''          N/A  \
-               ge  1  'foo  bar'  'foo  bar'  N/A         N/A  \
-               ge  1  'foo  bar'  N/A         N/A         N/A  \
-               ge  1  'foo  bar'  bar         foo         ''   \
-               ge  1  'foo  bar'  bar         foo         ' '  \
-               ge  1  'foo  bar'  baz         bar         foo  \
-               ge  1  'foo  bar'  fo          ba          N/A  \
-               ge  1  'foo  bar'  foo         bar         ''   \
-               ge  1  'foo  bar'  foo         bar         ' '  \
-               ge  1  'foo  bar'  foo         bar         baz  \
-               ge  1  'foo  bar'  o           a           N/A  \
-               ge  1  'foo  bar'  oo          ar          N/A  \
-               eq  0  'foo  bar'  foo         bar         N/A  \
-               eq  0  'foo  bar'  bar         foo         N/A
+               ge  1  default  N/A           N/A         N/A         N/A  \
+               ge  1  default  ' foo  bar '  ''          N/A         N/A  \
+               ge  1  default  ' foo  bar '  ''          ' '         N/A  \
+               ge  1  default  ' foo  bar '  ''          ' bar'      N/A  \
+               ge  1  default  ' foo  bar '  ''          'foo '      N/A  \
+               ge  1  default  ' foo  bar '  ''          'foo  bar'  N/A  \
+               ge  1  default  ' foo  bar '  ' '         ''          N/A  \
+               ge  1  default  ' foo  bar '  ' '         ' '         N/A  \
+               ge  1  default  ' foo  bar '  ' '         N/A         N/A  \
+               ge  1  default  ' foo  bar '  ' bar'      ''          N/A  \
+               ge  1  default  ' foo  bar '  ' bar'      N/A         N/A  \
+               ge  1  default  ' foo  bar '  'foo '      ''          N/A  \
+               ge  1  default  ' foo  bar '  'foo '      ' bar'      N/A  \
+               ge  1  default  ' foo  bar '  'foo '      N/A         N/A  \
+               ge  1  default  ' foo  bar '  'foo  bar'  ''          N/A  \
+               ge  1  default  ' foo  bar '  'foo  bar'  N/A         N/A  \
+               ge  1  default  ' foo  bar '  N/A         N/A         N/A  \
+               ge  1  default  ' foo  bar '  bar         foo         ''   \
+               ge  1  default  ' foo  bar '  bar         foo         ' '  \
+               ge  1  default  ' foo  bar '  baz         bar         foo  \
+               ge  1  default  ' foo  bar '  fo          ba          N/A  \
+               ge  1  default  ' foo  bar '  foo         bar         ''   \
+               ge  1  default  ' foo  bar '  foo         bar         ' '  \
+               ge  1  default  ' foo  bar '  foo         bar         baz  \
+               ge  1  default  ' foo  bar '  o           a           N/A  \
+               ge  1  default  ' foo  bar '  oo          ar          N/A  \
+               eq  0  default  ' foo  bar '  foo         bar         N/A  \
+               eq  0  default  ' foo  bar '  bar         foo         N/A  \
+               ge  1  ', '     N/A           N/A         N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  ''          N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  ''          ' '         N/A  \
+               ge  1  ', '     ' foo ,bar, ' ''          ','         N/A  \
+               ge  1  ', '     ' foo  bar '  ''          ' bar'      N/A  \
+               ge  1  ', '     ' foo ,bar '  ''          ',bar'      N/A  \
+               ge  1  ', '     ' foo  bar '  ''          'foo '      N/A  \
+               ge  1  ', '     ' foo, bar '  ''          'foo,'      N/A  \
+               ge  1  ', '     ' foo  bar '  ''          'foo  bar'  N/A  \
+               ge  1  ', '     ' foo  bar '  ' '         ''          N/A  \
+               ge  1  ', '     ' foo,bar, '  ','         ''          N/A  \
+               ge  1  ', '     ' foo  bar '  ' '         ' '         N/A  \
+               ge  1  ', '     ',foo,,bar,'  ','         ','         N/A  \
+               ge  1  ', '     ' foo  bar '  ' '         N/A         N/A  \
+               ge  1  ', '     ',foo,,bar,'  ','         N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  ' bar'      ''          N/A  \
+               ge  1  ', '     'foo,bar,'    ',bar'      ''          N/A  \
+               ge  1  ', '     ' foo  bar '  ' bar'      N/A         N/A  \
+               ge  1  ', '     ',foo,,bar,'  ',bar'      N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  'foo '      ''          N/A  \
+               ge  1  ', '     'foo,bar,'    'foo,'      ''          N/A  \
+               ge  1  ', '     ' foo  bar '  'foo '      ' bar'      N/A  \
+               ge  1  ', '     ',foo,,bar,'  'foo,'      ',bar'      N/A  \
+               ge  1  ', '     ' foo  bar '  'foo '      N/A         N/A  \
+               ge  1  ', '     ',foo,,bar,'  'foo,'      N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  'foo  bar'  ''          N/A  \
+               ge  1  ', '     'foo,bar,'    'foo,bar'   ''          N/A  \
+               ge  1  ', '     ' foo  bar '  'foo  bar'  N/A         N/A  \
+               ge  1  ', '     ',foo,,bar,'  'foo,,bar'  N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  N/A         N/A         N/A  \
+               ge  1  ', '     ' foo  bar '  bar         foo         ''   \
+               ge  1  ', '     ' foo,bar  '  bar         foo         ''   \
+               ge  1  ', '     ' foo  bar '  bar         foo         ' '  \
+               ge  1  ', '     ' foo,,bar '  bar         foo         ','  \
+               ge  1  ', '     ' foo  bar '  baz         bar         foo  \
+               ge  1  ', '     ',foo,,bar,'  baz         bar         foo  \
+               ge  1  ', '     ' foo  bar '  fo          ba          N/A  \
+               ge  1  ', '     ',foo,,bar,'  fo          ba          N/A  \
+               ge  1  ', '     ' foo  bar '  foo         bar         ''   \
+               ge  1  ', '     ' foo,bar '   foo         bar         ''   \
+               ge  1  ', '     ' foo  bar '  foo         bar         ' '  \
+               ge  1  ', '     ' foo,,bar '  foo         bar         ','  \
+               ge  1  ', '     ' foo  bar '  foo         bar         baz  \
+               ge  1  ', '     ',foo,,bar,'  foo         bar         baz  \
+               ge  1  ', '     ' foo  bar '  o           a           N/A  \
+               ge  1  ', '     ',foo,,bar,'  o           a           N/A  \
+               ge  1  ', '     ' foo  bar '  oo          ar          N/A  \
+               ge  1  ', '     ',foo,,bar,'  oo          ar          N/A  \
+               eq  0  ', '     ' foo  bar '  foo         bar         N/A  \
+               eq  0  ', '     ',foo  bar,'  foo         bar         N/A  \
+               eq  0  ', '     ' foo,,bar '  foo         bar         N/A  \
+               eq  0  ', '     ',foo,,bar,'  foo         bar         N/A  \
+               eq  0  ', '     ' foo  bar '  bar         foo         N/A  \
+               eq  0  ', '     ',foo  bar,'  bar         foo         N/A  \
+               eq  0  ', '     ' foo,,bar '  bar         foo         N/A  \
+               eq  0  ', '     ',foo,,bar,'  bar         foo         N/A
 
        callback() {
                shift
-               test_description="contains_all $(quote_args "$@")"
-               contains_all "$@"
+               ifs=$1
+               shift
+               if [ "${ifs}" = "default" ]; then
+                       test_description="contains_all $(quote_args "$@")"
+                       contains_all "$@"
+               else
+                       test_description="IFS='${ifs}' contains_all 
$(quote_args "$@")"
+                       IFS=${ifs} contains_all "$@"
+               fi
        }
 
-       iterate_tests 6 "$@"
+       iterate_tests 7 "$@"
 }
 
 test_contains_any() {

Reply via email to