# This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # tests of various aspects of pathname expansion, mostly dealing with bracket # expressions # # Derived from tests contributed by Koichi Murase LC_COLLATE=C ORIG_DIR=$PWD : ${TMPDIR:=/tmp} ${BUILD_DIR:=$ORIG_DIR} trap 'rm -rf $TESTDIR $WORK_DIR' EXIT WORK_DIR=${TMPDIR}/globtest-$$ mkdir $WORK_DIR || { echo "glob-bracket: cannot create directory $WORK_DIR" >&2 exit 1 } cd $WORK_DIR || { echo "glob-bracket: cannot cd to directory $WORK_DIR" >&2 exit 1 } eval $(grep -E '^(CC |SHOBJ_).*=' $BUILD_DIR/examples/loadables/Makefile | sed -e 's/[ ]*=[ ]*/="/' -e 's/\$@/strmatch/' -e 's/$/"/' ) if [ "$SHOBJ_STATUS" != "supported" ]; then echo "glob-bracket: shared objects not supported, cannot continue" >&2 exit 2 fi # we assume gcc as a default here : ${CC:=gcc} cat > fnmatch.c <<-EOF #include #include #include int main(int argc, char **argv) { if (2 >= argc) { fprintf(stderr, "usage: fnmatch string pattern\n"); exit(2); } #ifdef FNM_EXTMATCH int flags = FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH; #else int flags = FNM_PATHNAME | FNM_PERIOD; #endif if (fnmatch(argv[2], argv[1], flags) == 0) return 0; return 1; } EOF $CC -O2 -o fnmatch fnmatch.c rm -f fnmatch.c if [ ! -f fnmatch ] ; then echo "glob-bracket: cannot create fnmatch executable" >&2 exit 2 fi cat > strmatch.c <<-EOF #define BUILTIN_ENABLED 0x01 struct word_desc { char* word; int flags; }; struct word_list { struct word_list* next; struct word_desc* word; }; struct builtin { const char* name; int (*function)(struct word_list*); int flags; const char** long_doc; const char* short_doc; char* handle; }; /*#include */ int strmatch(char *pattern, char *string, int flags); #define FNM_PATHNAME (1 << 0) #define FNM_NOESCAPE (1 << 1) #define FNM_PERIOD (1 << 2) #define FNM_LEADING_DIR (1 << 3) #define FNM_CASEFOLD (1 << 4) #define FNM_EXTMATCH (1 << 5) #define FNM_FIRSTCHAR (1 << 6) #define FNM_DOTDOT (1 << 7) static int strmatch_builtin(struct word_list* list) { char *str, *pat; if (!list || !list->word) return 2; str = list->word->word; if (!list->next || !list->next->word) return 2; pat = list->next->word->word; if (strmatch (pat, str, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0) return 0; return 1; } static const char* strmatch_doc[] = { "This is a builtin to test the behavior of strmatch", 0 }; struct builtin strmatch_struct = { "strmatch", strmatch_builtin, BUILTIN_ENABLED, strmatch_doc, "strmatch string pattern", 0, }; EOF ${SHOBJ_CC} ${SHOBJ_CFLAGS} -c -o strmatch.o strmatch.c rm -f strmatch.c ${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o strmatch.so strmatch.o ${SHOBJ_LIBS} rm -f strmatch.o if [ ! -f strmatch.so ] ; then echo "glob-bracket: cannot create strmatch loadable builtin" >&2 exit 2 fi enable -f ./strmatch.so strmatch || { echo "glob-bracket: cannot load strmatch builtin" >&2 exit 2 } check_count=1 if [ -z "$BASH_TSTOUT" ]; then yes=$'\033[32myes\033[m' no=$'\033[31mno\033[m' else yes=yes no=no fi function check { # bash impl if strmatch "$2" "$1"; then local strmatch=$yes else local strmatch=$no fi # fnmatch local expect=${3-} if [[ ! $expect ]]; then if $WORK_DIR/fnmatch "$2" "$1"; then expect=$yes else expect=$no fi fi printf '#%d: pat=%-20s str=%-16s %s/%s\n' "$((check_count++))" "$1" "$2" "$strmatch" "$expect" } function pcheck { local GLOBIGNORE=$1 # bash impl local -a f=(*/*/efg*) if [[ $f == '*/*/efg*' ]]; then local strmatch=$yes else local strmatch=$no fi # Linux fnmatch local fnmatch=${2-} if [[ ! $fnmatch ]]; then if $WORK_DIR/fnmatch ab/cd/efg "$1"; then fnmatch=$yes else fnmatch=$no fi fi printf '#%d: pat=%-16s %s/%s\n' "$((check_count++))" "$1" "$strmatch" "$fnmatch" } TESTDIR=${TMPDIR}/pathtest-$$ TESTPATH=${TESTDIR}/ab/cd/efg mkdir -p $TESTPATH if [ -d "$TESTPATH" ] && cd "$TESTDIR"; then echo '--- $GLOBIGNORE vs fnmatch(3) ---' pcheck 'ab/cd/efg' pcheck 'ab[/]cd/efg' pcheck 'ab[/a]cd/efg' pcheck 'ab[a/]cd/efg' pcheck 'ab[!a]cd/efg' pcheck 'ab[.-0]cd/efg' pcheck '*/*/efg' pcheck '*[/]*/efg' pcheck '*[/a]*/efg' pcheck '*[a/]*/efg' pcheck '*[!a]*/efg' pcheck '*[.-0]*/efg' pcheck '*/*/efg' pcheck '*[b]/*/efg' pcheck '*[ab]/*/efg' pcheck '*[ba]/*/efg' pcheck '*[!a]/*/efg' pcheck '*[a-c]/*/efg' shopt -s extglob pcheck 'ab@(/)cd/efg' "$yes" pcheck '*@(/)cd/efg' "$no" pcheck '*/cd/efg' shopt -u extglob cd "$WORK_DIR" fi echo echo '---Tests for a slash in bracket expressions---' check 'ab[/]ef' 'ab[/]ef' "$yes" check 'ab[/]ef' 'ab/ef' "$no" check 'ab[c/d]ef' 'ab[c/d]ef' "$yes" check 'ab[c/d]ef' 'abcef' "$no" check 'ab[.-/]ef' 'ab[.-/]ef' "$yes" check 'ab[.-/]ef' 'ab.ef' "$no" check 'ab[[=/=]]ef' 'ab[[=/=]]ef' "$yes" check 'ab[[=/=]]ef' 'ab/ef' "$no" check 'ab[[=c=]/]ef' 'ab[=/]ef' "$yes" check 'ab[[=c=]/]ef' 'abcef' "$no" check 'ab[[:alpha:]/]ef' 'ab[:/]ef' "$yes" check 'ab[[:alpha:]/]ef' 'abxef' "$no" check 'ab[/[abc]]ef' 'ab[/c]ef' "$yes" check 'ab[/[abc]]ef' 'abc]ef' "$no" check 'ab[c[=/=]]ef' 'ab[c[=/=]]ef' "$yes" check 'ab[c[=/=]]ef' 'abc[=/=]ef' "$no" check 'ab[c[=/=]]ef' 'abcef' "$no" check 'a[b\/c]' 'a[b/c]' "$yes" check 'a[b\/c]' 'ab' "$no" check 'a[b\/c]' 'ac' "$no" echo echo '---Tests for incomplete bracket expressions---' check 'ab[c' 'ab[c' "$yes" check 'ab[c' 'abc' "$no" check 'ab[c[=d=' 'ab[c[=d=' "$yes" check 'ab[c[=d=' 'abc' "$no" check 'ab[c[.d' 'ab[c[.d' "$yes" check 'ab[c[.d' 'abc' "$no" check 'ab[c[:alpha:' 'ab[c[:alpha:' "$yes" check 'ab[c[:alpha:' 'abc' "$no" check 'ab[c-' 'ab[c-' "$yes" check 'ab[c-' 'abc' "$no" check 'ab[c\' 'ab[c\' "$yes" check 'ab[c\' 'abc' "$no" check 'ab[[\' 'ab[[\' "$yes" check 'ab[[\' 'ab[' "$no" echo echo '--- PATSCAN vs BRACKMATCH ---' check '@([[.].])A])' ']' "$yes" check '@([[.].])A])' '==]A])' "$no" check '@([[.].])A])' 'AA])' "$no" check '@([[=]=])A])' ']' "$no" check '@([[=]=])A])' '==]A])' "$yes" check '@([[=]=])A])' 'AA])' "$no" echo echo '--- BRACKMATCH: after match vs before match ---' check '[[=]=]ab]' 'a' "$no" check '[[.[=.]ab]' 'a' "$yes" check '[[.[==].]ab]' 'a' "$yes" echo check '[a[=]=]b]' 'a' "$no" check '[a[.[=.]b]' 'a' "$yes" check '[a[.[==].]b]' 'a' "$yes" echo check '[a[=]=]b]' 'b' "$no" check '[a[=]=]b]' 'a=]b]' "$yes" check '[a[.[=.]b]' 'b' "$yes" check '[a[.[=.]b]' 'ab]' "$no" check '[a[.[==].]b]' 'b' "$yes" check '[a[.[==].]b]' 'ab]' "$no" echo echo '--- incomplete POSIX brackets ---' check 'x[a[:y]' 'x[' "$yes" check 'x[a[:y]' 'x:' "$yes" check 'x[a[:y]' 'xy' "$yes" check 'x[a[:y]' 'x[ay' "$no" echo check 'x[a[.y]' 'x[' "$yes" check 'x[a[.y]' 'x.' "$yes" check 'x[a[.y]' 'xy' "$yes" check 'x[a[.y]' 'x[ay' "$no" echo check 'x[a[=y]' 'x[' "$yes" check 'x[a[=y]' 'x=' "$yes" check 'x[a[=y]' 'xy' "$yes" check 'x[a[=y]' 'x[ay' "$no" echo echo '--- MISC tests ---' check 'a\' 'a\' "$yes" cd $ORIG_DIR exit 0