1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-24 15:04:13 +00:00
cde/src/cmd/ksh93/tests/glob.sh
Martijn Dekker 5312a59d5a Skip '.' and '..' when globbing patterns like .*
There are convincing arguments why including '.' and '..' in the
result of pathname expansion is actively harmful. See:
https://www.austingroupbugs.net/view.php?id=1228
https://github.com/ksh93/ksh/issues/58#issuecomment-653716846

pdksh, mksh and zsh already skip these special traversal names
in all cases. This commit makes ksh act like these shells.

Since passing '.' and especially '..' as arguments to commands like
'chmod -R' and 'cp -r' may cause harm, this change seems likely to
fix more legacy scripts than it breaks. I'm unaware of anyone ever
having come up with a concrete use case for the old behaviour.

This change also fixes the bug that '.' and '..' failed to be
ignored as documented if FIGNORE is set.

src/lib/libast/misc/glob.c: glob_dir():
- Explicitly skip any matching '.' and '..' in all cases.

src/cmd/ksh93/tests/glob.sh:
- Add test_glob() tests for '*' and '.*'.

src/cmd/ksh93/sh.1: File Name Generation:
- Update to match new behaviour.

Resolves: https://github.com/ksh93/ksh/issues/58
2020-08-10 00:35:53 +01:00

381 lines
11 KiB
Bash
Executable file

########################################################################
# #
# This software is part of the ast package #
# Copyright (c) 1982-2012 AT&T Intellectual Property #
# and is licensed under the #
# Eclipse Public License, Version 1.0 #
# by AT&T Intellectual Property #
# #
# A copy of the License is available at #
# http://www.eclipse.org/org/documents/epl-v10.html #
# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
# #
# Information and Software Systems Research #
# AT&T Research #
# Florham Park NJ #
# #
# David Korn <dgk@research.att.com> #
# #
########################################################################
function err_exit
{
print -u2 -r $'\t'"${Command}[$1] ${@:2}"
((Errors++))
}
alias err_exit='err_exit $LINENO'
Command=${0##*/}
integer aware=0 contrary=0 Errors=0 ignorant=0
[[ -d $tmp && -w $tmp ]] || { err\_exit "$LINENO" '$tmp not set; run this from shtests. Aborting.'; exit 1; }
function test_glob
{
typeset lineno expected drop arg got sep op val add del
lineno=$1
shift
if [[ $1 == --* ]]
then del=${1#--}
shift
fi
if [[ $1 == ++* ]]
then add=${1#++}
shift
fi
expected=$1
shift
if (( contrary ))
then if [[ $expected == "<Beware> "* ]]
then expected=${expected#"<Beware> "}
expected="$expected <Beware>"
fi
if [[ $expected == *"<aXb> <abd>"* ]]
then expected=${expected/"<aXb> <abd>"/"<abd> <aXb>"}
fi
fi
for arg
do got="$got$sep<$arg>"
sep=" "
done
if (( ignorant && aware ))
then if [[ $del ]]
then got="<$del> $got"
fi
if [[ $add ]]
then expected="<$add> $expected"
fi
fi
if [[ $got != "$expected" ]]
then 'err_exit' $lineno "glob -- expected '$expected', got '$got'"
fi
}
alias test_glob='test_glob $LINENO'
function test_case
{
typeset lineno expected subject pattern got
lineno=$1 expected=$2 subject=$3 pattern=$4
eval "
case $subject in
$pattern) got='<match>' ;;
*) got='<nomatch>' ;;
esac
"
if [[ $got != "$expected" ]]
then 'err_exit' $lineno "case $subject in $pattern) -- expected '$expected', got '$got'"
fi
}
alias test_case='test_case $LINENO'
unset undefined
cd $tmp || { err_exit "cd $tmp failed"; exit 1; }
export LC_COLLATE=C
touch B b
set -- *
case $* in
'b B') contrary=1 ;;
b|B) ignorant=1 ;;
esac
set -- $(LC_ALL=C sh -c 'echo [a-c]')
case $* in
B) aware=1 ;;
esac
rm -rf *
touch a b c d abc abd abe bb bcd ca cb dd de Beware
mkdir bdir
test_glob '<a> <abc> <abd> <abe> <X*>' a* X*
test_glob '<a> <abc> <abd> <abe>' \a*
if ( set --nullglob ) 2>/dev/null
then
set --nullglob
test_glob '<a> <abc> <abd> <abe>' a* X*
set --nonullglob
fi
if ( set --failglob ) 2>/dev/null
then
set --failglob
mkdir tmp
touch tmp/l1 tmp/l2 tmp/l3
test_glob '' tmp/l[12] tmp/*4 tmp/*3
test_glob '' tmp/l[12] tmp/*4 tmp/*3
rm -r tmp
set --nofailglob
fi
test_glob '<bdir/>' b*/
test_glob '<*>' \*
test_glob '<a*>' 'a*'
test_glob '<a*>' a\*
test_glob '<c> <ca> <cb> <a*> <*q*>' c* a\* *q*
test_glob '<**>' "*"*
test_glob '<**>' \**
test_glob '<\.\./*/>' "\.\./*/"
test_glob '<s/\..*//>' 's/\..*//'
test_glob '</^root:/{s/^[!:]*:[!:]*:\([!:]*\).*$/\1/>' "/^root:/{s/^[!:]*:[!:]*:\([!:]*\).*"'$'"/\1/"
test_glob '<abc> <abd> <abe> <bb> <cb>' [a-c]b*
test_glob ++Beware '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>' [a-y]*[!c]
test_glob '<abd> <abe>' a*[!c]
touch a-b aXb
test_glob '<a-b> <aXb>' a[X-]b
touch .x .y
test_glob --Beware '<Beware> <d> <dd> <de>' [!a-c]*
if mkdir a\*b 2>/dev/null
then
touch a\*b/ooo
test_glob '<a*b/ooo>' a\*b/*
test_glob '<a*b/ooo>' a\*?/*
test_case '<match>' '!7' '*\!*'
test_case '<match>' 'r.*' '*.\*'
test_glob '<abc>' a[b]c
test_glob '<abc>' a["b"]c
test_glob '<abc>' a[\b]c
test_glob '<abc>' a?c
test_case '<match>' 'abc' 'a"b"c'
test_case '<match>' 'abc' 'a*c'
test_case '<nomatch>' 'abc' '"a?c"'
test_case '<nomatch>' 'abc' 'a\*c'
test_case '<nomatch>' 'abc' 'a\[b]c'
test_case '<match>' '"$undefined"' '""'
test_case '<match>' 'abc' 'a["\b"]c'
rm -rf mkdir a\*b
fi
mkdir man
mkdir man/man1
touch man/man1/sh.1
test_glob '<man/man1/sh.1>' */man*/sh.*
test_glob '<man/man1/sh.1>' $(echo */man*/sh.*)
test_glob '<man/man1/sh.1>' "$(echo */man*/sh.*)"
test_case '<match>' 'abc' 'a***c'
test_case '<match>' 'abc' 'a*****?c'
test_case '<match>' 'abc' '?*****??'
test_case '<match>' 'abc' '*****??'
test_case '<match>' 'abc' '*****??c'
test_case '<match>' 'abc' '?*****?c'
test_case '<match>' 'abc' '?***?****c'
test_case '<match>' 'abc' '?***?****?'
test_case '<match>' 'abc' '?***?****'
test_case '<match>' 'abc' '*******c'
test_case '<match>' 'abc' '*******?'
test_case '<match>' 'abcdecdhjk' 'a*cd**?**??k'
test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k'
test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k***'
test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k'
test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k**'
test_case '<match>' 'abcdecdhjk' 'a****c**?**??*****'
test_case '<match>' "'-'" '[-abc]'
test_case '<match>' "'-'" '[abc-]'
test_case '<match>' "'\\'" '\\'
test_case '<match>' "'\\'" '[\\]'
test_case '<match>' "'\\'" "'\\'"
test_case '<match>' "'['" '[[]'
test_case '<match>' '[' '[[]'
test_case '<match>' "'['" '['
test_case '<match>' '[' '['
test_case '<match>' "'[abc'" "'['*"
test_case '<nomatch>' "'[abc'" '[*'
test_case '<match>' '[abc' "'['*"
test_case '<nomatch>' '[abc' '[*'
test_case '<match>' 'abd' "a[b/c]d"
test_case '<match>' 'a/d' "a[b/c]d"
test_case '<match>' 'acd' "a[b/c]d"
test_case '<match>' "']'" '[]]'
test_case '<match>' "'-'" '[]-]'
test_case '<match>' 'p' '[a-\z]'
test_case '<match>' '"/tmp"' '[/\\]*'
test_case '<nomatch>' 'abc' '??**********?****?'
test_case '<nomatch>' 'abc' '??**********?****c'
test_case '<nomatch>' 'abc' '?************c****?****'
test_case '<nomatch>' 'abc' '*c*?**'
test_case '<nomatch>' 'abc' 'a*****c*?**'
test_case '<nomatch>' 'abc' 'a********???*******'
test_case '<nomatch>' "'a'" '[]'
test_case '<nomatch>' 'a' '[]'
test_case '<nomatch>' "'['" '[abc'
test_case '<nomatch>' '[' '[abc'
test_glob ++Beware '<b> <bb> <bcd> <bdir>' b*
test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]*
if ( set --nocaseglob ) 2>/dev/null
then
set --nocaseglob
test_glob '<Beware> <b> <bb> <bcd> <bdir>' b*
test_glob '<Beware> <b> <bb> <bcd> <bdir>' [b]*
test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]*
set --nonocaseglob
fi
if ( set -f ) 2>/dev/null
then
set -f
test_glob '<*>' *
set +f
fi
if ( set --noglob ) 2>/dev/null
then
set --noglob
test_glob '<*>' *
set --glob
fi
FIGNORE='@(.*|*)'
test_glob '<*>' *
FIGNORE='@(.*|*c|*e|?)'
test_glob '<a-b> <aXb> <abd> <bb> <bcd> <bdir> <ca> <cb> <dd> <man>' *
FIGNORE='@(.*|*b|*d|?)'
test_glob '<Beware> <abc> <abe> <bdir> <ca> <de> <man>' *
FIGNORE=
test_glob '<man/man1/sh.1>' */man*/sh.*
test_glob '<.x> <.y> <Beware> <a> <a-b> <aXb> <abc> <abd> <abe> <b> <bb> <bcd> <bdir> <c> <ca> <cb> <d> <dd> <de> <man>' *
test_glob '<.x> <.y>' .*
FIGNORE='@(*[abcd]*)'
test_glob '<.x> <.y>' *
test_glob '<.x> <.y>' .*
unset FIGNORE
test_glob '<bb> <ca> <cb> <dd> <de>' ??
test_glob '<man/man1/sh.1>' */man*/sh.*
test_glob '<Beware> <a> <a-b> <aXb> <abc> <abd> <abe> <b> <bb> <bcd> <bdir> <c> <ca> <cb> <d> <dd> <de> <man>' *
test_glob '<.x> <.y>' .*
GLOBIGNORE='.*:*'
set -- *
if [[ $1 == '*' ]]
then
GLOBIGNORE='.*:*c:*e:?'
test_glob '<>' *
GLOBIGNORE='.*:*b:*d:?'
test_glob '<>' *
unset GLOBIGNORE
test_glob '<>' *
test_glob '<man/man1/sh.1>' */man*/sh.*
GLOBIGNORE=
test_glob '<man/man1/sh.1>' */man*/sh.*
fi
unset GLOBIGNORE
function test_sub
{
x='${subject'$2'}'
eval g=$x
if [[ "$g" != "$3" ]]
then 'err_exit' $1 subject="'$subject' $x failed, expected '$3', got '$g'"
fi
}
alias test_sub='test_sub $LINENO'
set --noglob --nobraceexpand
subject='A regular expressions test'
test_sub '/e/#' 'A r#gular expressions test'
test_sub '//e/#' 'A r#gular #xpr#ssions t#st'
test_sub '/[^e]/#' '# regular expressions test'
test_sub '//[^e]/#' '###e######e###e########e##'
test_sub '/+(e)/#' 'A r#gular expressions test'
test_sub '//+(e)/#' 'A r#gular #xpr#ssions t#st'
test_sub '/@-(e)/#' 'A r#gular expressions test'
test_sub '//@-(e)/#' 'A r#gular #xpr#ssions t#st'
test_sub '/?(e)/#' '#A regular expressions test'
test_sub '//?(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#'
test_sub '/*(e)/#' '#A regular expressions test'
test_sub '//*(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#'
test_sub '//@(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//@-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//+(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//+-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//@(+(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//@(+-(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st'
test_sub '//-(e)/#' 'A regular expressions test'
test_sub '//--(e)/#' 'A regular expressions test'
test_sub '//?(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//{0,1}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//*(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//{0,}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//@(?(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//@({0,1}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//@(*(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '//@({0,}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]'
test_sub '/?-(e)/#' '#A regular expressions test'
test_sub '/@(?-(e))/[\1]' '[]A regular expressions test'
test_sub '/!(e)/#' '#'
test_sub '//!(e)/#' '#'
test_sub '/@(!(e))/[\1]' '[A regular expressions test]'
test_sub '//@(!(e))/[\1]' '[A regular expressions test]'
subject='e'
test_sub '/!(e)/#' '#e'
test_sub '//!(e)/#' '#e#'
test_sub '/!(e)/[\1]' '[]e'
test_sub '//!(e)/[\1]' '[]e[]'
test_sub '/@(!(e))/[\1]' '[]e'
test_sub '//@(!(e))/[\1]' '[]e[]'
subject='a'
test_sub '/@(!(a))/[\1]' '[]a'
test_sub '//@(!(a))/[\1]' '[]a[]'
subject='aha'
test_sub '/@(!(a))/[\1]' '[aha]'
test_sub '//@(!(a))/[\1]' '[aha]'
test_sub '/@(!(aha))/[\1]' '[ah]a'
test_sub '//@(!(aha))/[\1]' '[ah][a]'
exit $((Errors<125?Errors:125))