summaryrefslogtreecommitdiff
path: root/bin/ksh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/ksh')
-rw-r--r--bin/ksh/tests/brkcont.t195
-rw-r--r--bin/ksh/tests/cdhist.t160
-rw-r--r--bin/ksh/tests/eglob.t138
-rw-r--r--bin/ksh/tests/glob.t96
-rw-r--r--bin/ksh/tests/heredoc.t72
-rw-r--r--bin/ksh/tests/history.t529
-rw-r--r--bin/ksh/tests/ifs.t162
-rw-r--r--bin/ksh/tests/integer.t218
-rw-r--r--bin/ksh/tests/read.t56
-rw-r--r--bin/ksh/tests/regress.t641
-rw-r--r--bin/ksh/tests/th813
-rw-r--r--bin/ksh/tests/th.sh21
-rw-r--r--bin/ksh/tests/unclass1.t97
-rw-r--r--bin/ksh/tests/unclass2.t166
-rw-r--r--bin/ksh/tests/version.t8
15 files changed, 3372 insertions, 0 deletions
diff --git a/bin/ksh/tests/brkcont.t b/bin/ksh/tests/brkcont.t
new file mode 100644
index 00000000000..1eb9c2581c9
--- /dev/null
+++ b/bin/ksh/tests/brkcont.t
@@ -0,0 +1,195 @@
+name: break-1
+description:
+ See if break breaks out of loops
+stdin:
+ for i in a b c; do echo $i; break; echo bad-$i; done
+ echo end-1
+ for i in a b c; do echo $i; break 1; echo bad-$i; done
+ echo end-2
+ for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ break
+ echo bad-$i
+ done
+ echo end-$i
+ done
+ echo end-3
+expected-stdout:
+ a
+ end-1
+ a
+ end-2
+ a:x
+ end-a
+ b:x
+ end-b
+ c:x
+ end-c
+ end-3
+---
+
+name: break-2
+description:
+ See if break breaks out of nested loops
+stdin:
+ for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ break 2
+ echo bad-$i
+ done
+ echo end-$i
+ done
+ echo end
+expected-stdout:
+ a:x
+ end
+---
+
+
+name: break-3
+description:
+ What if break used outside of any loops
+ (ksh88,ksh93 don't print error messages here)
+stdin:
+ break
+expected-stderr-pattern:
+ /.*break.*/
+---
+
+
+name: break-4
+description:
+ What if break N used when only N-1 loops
+ (ksh88,ksh93 don't print error messages here)
+stdin:
+ for i in a b c; do echo $i; break 2; echo bad-$i; done
+ echo end
+expected-stdout:
+ a
+ end
+expected-stderr-pattern:
+ /.*break.*/
+---
+
+
+name: break-5
+description:
+ Error if break argument isn't a number
+stdin:
+ for i in a b c; do echo $i; break abc; echo more-$i; done
+ echo end
+expected-stdout:
+ a
+expected-exit: e != 0
+expected-stderr-pattern:
+ /.*break.*/
+---
+
+
+name: continue-1
+description:
+ See if continue continues loops
+stdin:
+ for i in a b c; do echo $i; continue; echo bad-$i ; done
+ echo end-1
+ for i in a b c; do echo $i; continue 1; echo bad-$i; done
+ echo end-2
+ for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ continue
+ echo bad-$i-$j
+ done
+ echo end-$i
+ done
+ echo end-3
+expected-stdout:
+ a
+ b
+ c
+ end-1
+ a
+ b
+ c
+ end-2
+ a:x
+ a:y
+ a:z
+ end-a
+ b:x
+ b:y
+ b:z
+ end-b
+ c:x
+ c:y
+ c:z
+ end-c
+ end-3
+---
+
+
+name: continue-2
+description:
+ See if continue breaks out of nested loops
+stdin:
+ for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ continue 2
+ echo bad-$i-$j
+ done
+ echo end-$i
+ done
+ echo end
+expected-stdout:
+ a:x
+ b:x
+ c:x
+ end
+---
+
+
+name: continue-3
+description:
+ What if continue used outside of any loops
+ (ksh88,ksh93 don't print error messages here)
+stdin:
+ continue
+expected-stderr-pattern:
+ /.*continue.*/
+---
+
+
+name: continue-4
+description:
+ What if continue N used when only N-1 loops
+ (ksh88,ksh93 don't print error messages here)
+stdin:
+ for i in a b c; do echo $i; continue 2; echo bad-$i; done
+ echo end
+expected-stdout:
+ a
+ b
+ c
+ end
+expected-stderr-pattern:
+ /.*continue.*/
+---
+
+
+name: continue-5
+description:
+ Error if continue argument isn't a number
+stdin:
+ for i in a b c; do echo $i; continue abc; echo more-$i; done
+ echo end
+expected-stdout:
+ a
+expected-exit: e != 0
+expected-stderr-pattern:
+ /.*continue.*/
+---
+
+
diff --git a/bin/ksh/tests/cdhist.t b/bin/ksh/tests/cdhist.t
new file mode 100644
index 00000000000..720f7d60bcc
--- /dev/null
+++ b/bin/ksh/tests/cdhist.t
@@ -0,0 +1,160 @@
+name: cd-history
+description:
+ Test someone's CD history package (uses arrays)
+stdin:
+ # go to known place before doing anything
+ cd /
+
+ alias cd=_cd
+ function _cd
+ {
+ typeset -i cdlen i
+ typeset t
+
+ if [ $# -eq 0 ]
+ then
+ set -- $HOME
+ fi
+
+ if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists
+ then
+ typeset CDHIST
+ i=-1
+ while read -r t # read directory history file
+ do
+ CDHIST[i=i+1]=$t
+ done <$CDHISTFILE
+ fi
+
+ if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ]
+ then
+ _cdins # insert $PWD into cd history
+ fi
+
+ cdlen=${#CDHIST[*]} # number of elements in history
+
+ case "$@" in
+ -) # cd to new dir
+ if [ "$OLDPWD" = "" ] && ((cdlen>1))
+ then
+ 'print' ${CDHIST[1]}
+ 'cd' ${CDHIST[1]}
+ _pwd
+ else
+ 'cd' $@
+ _pwd
+ fi
+ ;;
+ -l) # print directory list
+ typeset -R3 num
+ ((i=cdlen))
+ while (((i=i-1)>=0))
+ do
+ num=$i
+ 'print' "$num ${CDHIST[i]}"
+ done
+ return
+ ;;
+ -[0-9]|-[0-9][0-9]) # cd to dir in list
+ if (((i=${1#-})<cdlen))
+ then
+ 'print' ${CDHIST[i]}
+ 'cd' ${CDHIST[i]}
+ _pwd
+ else
+ 'cd' $@
+ _pwd
+ fi
+ ;;
+ -*) # cd to matched dir in list
+ t=${1#-}
+ i=1
+ while ((i<cdlen))
+ do
+ case ${CDHIST[i]} in
+ *$t*)
+ 'print' ${CDHIST[i]}
+ 'cd' ${CDHIST[i]}
+ _pwd
+ break
+ ;;
+ esac
+ ((i=i+1))
+ done
+ if ((i>=cdlen))
+ then
+ 'cd' $@
+ _pwd
+ fi
+ ;;
+ *) # cd to new dir
+ 'cd' $@
+ _pwd
+ ;;
+ esac
+
+ _cdins # insert $PWD into cd history
+
+ if [ "$CDHISTFILE" ]
+ then
+ cdlen=${#CDHIST[*]} # number of elements in history
+
+ i=0
+ while ((i<cdlen))
+ do
+ 'print' -r ${CDHIST[i]} # update directory history
+ ((i=i+1))
+ done >$CDHISTFILE
+ fi
+ }
+
+ function _cdins # insert $PWD into cd history
+ { # meant to be called only by _cd
+ typeset -i i
+
+ ((i=0))
+ while ((i<${#CDHIST[*]})) # see if dir is already in list
+ do
+ if [ "${CDHIST[$i]}" = "$PWD" ]
+ then
+ break
+ fi
+ ((i=i+1))
+ done
+
+ if ((i>22)) # limit max size of list
+ then
+ i=22
+ fi
+
+ while (((i=i-1)>=0)) # bump old dirs in list
+ do
+ CDHIST[i+1]=${CDHIST[i]}
+ done
+
+ CDHIST[0]=$PWD # insert new directory in list
+ }
+
+
+ function _pwd
+ {
+ if [ -n "$ECD" ]
+ then
+ pwd 1>&6
+ fi
+ }
+ # Start of test
+ cd /tmp
+ cd /bin
+ cd /etc
+ cd -
+ cd -2
+ cd -l
+expected-stdout:
+ /bin
+ /tmp
+ 3 /
+ 2 /etc
+ 1 /bin
+ 0 /tmp
+---
diff --git a/bin/ksh/tests/eglob.t b/bin/ksh/tests/eglob.t
new file mode 100644
index 00000000000..ea69f635fcf
--- /dev/null
+++ b/bin/ksh/tests/eglob.t
@@ -0,0 +1,138 @@
+name: eglob-bad-1
+description:
+ Check that globbing isn't done when glob has syntax error
+perl-setup:
+ &touch("abcx", "abcz", "bbc");
+stdin:
+ echo !([*)*
+ echo +(a|b[)*
+expected-stdout:
+ !([*)*
+ +(a|b[)*
+---
+
+name: eglob-bad-2
+description:
+ Check that globbing isn't done when glob has syntax error
+ (at&t ksh fails this test)
+perl-setup:
+ &touch("abcx", "abcz", "bbc");
+stdin:
+ echo [a*(]*)z
+expected-stdout:
+ [a*(]*)z
+---
+
+name: eglob-infinite-plus
+description:
+ Check that shell doesn't go into infinite loop expanding +(...)
+ expressions.
+perl-setup:
+ &touch("abc");
+time-limit: 3
+stdin:
+ echo +()c
+ echo +()x
+ echo +(*)c
+ echo +(*)x
+expected-stdout:
+ +()c
+ +()x
+ abc
+ +(*)x
+---
+
+name: eglob-subst-1
+description:
+ Check that eglobbing isn't done on substitution results
+perl-setup:
+ &touch("abc");
+stdin:
+ x='@(*)'
+ echo $x
+expected-stdout:
+ @(*)
+---
+
+name: eglob-nomatch-1
+description:
+ Check that the pattern doesn't match
+stdin:
+ echo no-file+(a|b)stuff
+ echo no-file+(a*(c)|b)stuff
+expected-stdout:
+ no-file+(a|b)stuff
+ no-file+(a*(c)|b)stuff
+---
+
+name: eglob-match-1
+description:
+ Check that the pattern matches correctly
+perl-setup:
+ &touch("abd", "acd");
+stdin:
+ echo a+(b|c)d
+ echo a!(@(b|B))d
+ echo a[b*(foo|bar)]d
+expected-stdout:
+ abd acd
+ acd
+ abd
+---
+
+name: eglob-case-1
+description:
+ Simple negation tests
+stdin:
+ case foo in !(foo|bar)) echo yes;; *) echo no;; esac
+ case bar in !(foo|bar)) echo yes;; *) echo no;; esac
+expected-stdout:
+ no
+ no
+---
+
+name: eglob-case-2
+description:
+ Simple kleene tests
+stdin:
+ case foo in *(a|b[)) echo yes;; *) echo no;; esac
+ case foo in *(a|b[)|f*) echo yes;; *) echo no;; esac
+ case '*(a|b[)' in *(a|b[)) echo yes;; *) echo no;; esac
+expected-stdout:
+ no
+ yes
+ yes
+---
+
+name: eglob-trim-1
+description:
+ Eglobing in trim expressions...
+ (at&t ksh fails this - docs say # matches shortest string, ## matches
+ longest...)
+stdin:
+ x=abcdef
+ echo 1: ${x#a|abc}
+ echo 2: ${x##a|abc}
+ echo 3: ${x%def|f}
+ echo 4: ${x%%f|def}
+expected-stdout:
+ 1: bcdef
+ 2: def
+ 3: abcde
+ 4: abc
+---
+
+name: eglob-trim-2
+description:
+ Check eglobing works in trims...
+stdin:
+ x=abcdef
+ echo ${x#*(a|b)cd}
+ echo "${x#*(a|b)cd}"
+ echo ${x#"*(a|b)cd"}
+expected-stdout:
+ ef
+ ef
+ abcdef
+---
+
diff --git a/bin/ksh/tests/glob.t b/bin/ksh/tests/glob.t
new file mode 100644
index 00000000000..c7d8e26808d
--- /dev/null
+++ b/bin/ksh/tests/glob.t
@@ -0,0 +1,96 @@
+name: glob-bad-1
+description:
+ Check that globbing isn't done when glob has syntax error
+perl-setup:
+ mkdir("[x", 0777) || die "couldn't make directory [x - $!\n";
+ &touch("[x/foo");
+stdin:
+ echo [*
+ echo *[x
+ echo [x/*
+expected-stdout:
+ [*
+ *[x
+ [x/foo
+---
+
+name: glob-bad-2
+description:
+ Check that symbolic links aren't stat()'d
+perl-setup:
+ mkdir("dir", 0777) || die "couldn't make directory dir - $!\n";
+ &touch("dir/abc");
+ symlink("non-existent-file", "dir/abc");
+stdin:
+ echo d*/*
+ echo d*/abc
+expected-stdout:
+ dir/abc
+ dir/abc
+---
+
+name: glob-range-1
+description:
+ Test range matching
+perl-setup:
+ &touch(".bc", "abc", "bbc", "cbc", "-bc");
+stdin:
+ echo [ab-]*
+ echo [-ab]*
+ echo [!-ab]*
+ echo [!ab]*
+ echo []ab]*
+expected-stdout:
+ -bc abc bbc
+ -bc abc bbc
+ cbc
+ -bc cbc
+ abc bbc
+---
+
+name: glob-range-2
+description:
+ Test range matching
+ (at&t ksh fails this; POSIX says invalid)
+perl-setup:
+ &touch("abc");
+stdin:
+ echo [a--]*
+expected-stdout:
+ [a--]*
+---
+
+name: glob-range-3
+description:
+ Check that globbing matches the right things...
+perl-setup:
+ &touch("a\302c");
+stdin:
+ echo a[Á-Ú]*
+expected-stdout:
+ aÂc
+---
+
+name: glob-range-4
+description:
+ Results unspecified according to POSIX
+perl-setup:
+ &touch(".bc");
+stdin:
+ echo [a.]*
+expected-stdout:
+ [a.]*
+---
+
+name: glob-range-5
+description:
+ Results unspecified according to POSIX
+ (at&t ksh treats this like [a-cc-e]*)
+perl-setup:
+ &touch("abc", "bbc", "cbc", "dbc", "ebc", "-bc");
+stdin:
+ echo [a-c-e]*
+expected-stdout:
+ -bc abc bbc cbc ebc
+---
+
diff --git a/bin/ksh/tests/heredoc.t b/bin/ksh/tests/heredoc.t
new file mode 100644
index 00000000000..27c28302258
--- /dev/null
+++ b/bin/ksh/tests/heredoc.t
@@ -0,0 +1,72 @@
+name: heredoc-1
+description:
+ Check ordering/content of redundent here documents.
+stdin:
+ cat << EOF1 << EOF2
+ hi
+ EOF1
+ there
+ EOF2
+expected-stdout:
+ there
+---
+
+name: heredoc-2
+description:
+ Check quoted here-doc is protected.
+stdin:
+ a=foo
+ cat << 'EOF'
+ hi\
+ there$a
+ stuff
+ EOF
+expected-stdout:
+ hi\
+ there$a
+ stuff
+---
+
+name: heredoc-3
+description:
+ Check quoted here-documents don't have \newline processing done
+ on them.
+stdin:
+ cat << 'EOF'
+ hi\
+ there
+ EO\
+ F
+ EOF
+ true
+expected-stdout:
+ hi\
+ there
+ EO\
+ F
+---
+
+name: heredoc-4
+description:
+ Check that newline isn't needed after heredoc-delimiter marker.
+stdin: !
+ cat << EOF
+ hi
+ there
+ EOF
+expected-stdout:
+ hi
+ there
+---
+
+name: heredoc-5
+description:
+ Check that an error occurs if the heredoc-delimiter is missing.
+stdin: !
+ cat << EOF
+ hi
+ there
+expected-exit: e > 0
+expected-stderr-pattern: /.*/
+---
+
diff --git a/bin/ksh/tests/history.t b/bin/ksh/tests/history.t
new file mode 100644
index 00000000000..707327ed37c
--- /dev/null
+++ b/bin/ksh/tests/history.t
@@ -0,0 +1,529 @@
+# Not tested yet:
+# - commands in history file are not numbered negatively
+# (and a few hundred other things)
+
+name: history-basic
+description:
+ See if we can test history at all
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo hi
+ fc -l
+expected-stdout:
+ hi
+ 1 echo hi
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-e-minus-1
+description:
+ Check if more recent command is executed
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo hi
+ echo there
+ fc -e -
+expected-stdout:
+ hi
+ there
+ there
+expected-stderr-pattern:
+ /^X*echo there\nX*$/
+---
+
+name: history-e-minus-2
+description:
+ Check that repeated command is printed before command
+ is re-executed.
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ exec 2>&1
+ echo hi
+ echo there
+ fc -e -
+expected-stdout-pattern:
+ /X*hi\nX*there\nX*echo there\nthere\nX*/
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-e-minus-3
+description:
+ fc -e - fails when there is no history
+ (ksh93 has a bug that causes this to fail)
+ (ksh88 loops on this)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ fc -e -
+ echo ok
+expected-stdout:
+ ok
+expected-stderr-pattern:
+ /^X*.*:.*history.*\nX*$/
+---
+
+name: history-e-minus-4
+description:
+ "fc -e | more" works
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc
+ fc -e - | (read x; echo "A $x")
+ echo ok
+expected-stdout:
+ abc
+ A abc
+ ok
+expected-stderr-pattern:
+ /^X*echo abc\nX*/
+---
+
+name: history-e-minus-5
+description:
+ fc is replaced in history by new command.
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ echo ghi jkl
+ fc -e - echo
+ fc -l 2 4
+expected-stdout:
+ abc def
+ ghi jkl
+ ghi jkl
+ 2 echo ghi jkl
+ 3 echo ghi jkl
+ 4 fc -l 2 4
+expected-stderr-pattern:
+ /^X*echo ghi jkl\nX*$/
+---
+
+name: history-list-1
+description:
+ List lists correct range
+ (ksh88 fails 'cause it lists the fc command)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ fc -l -- -2
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ 2 echo line 2
+ 3 echo line 3
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-2
+description:
+ Lists oldest history if given pre-historic number
+ (ksh93 has a bug that causes this to fail)
+ (ksh88 fails 'cause it lists the fc command)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ fc -l -- -40
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ 1 echo line 1
+ 2 echo line 2
+ 3 echo line 3
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-3
+description:
+ Can give number `options' to fc
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ fc -l -3 -2
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ 2 echo line 2
+ 3 echo line 3
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-4
+description:
+ -1 refers to previous command
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ fc -l -1 -1
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ 4 echo line 4
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-5
+description:
+ List command stays in history
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ fc -l -1 -1
+ fc -l -2 -1
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ 4 echo line 4
+ 4 echo line 4
+ 5 fc -l -1 -1
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-6
+description:
+ HISTSIZE limits about of history kept.
+ (ksh88 fails 'cause it lists the fc command)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ echo line 5
+ fc -l
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ 4 echo line 4
+ 5 echo line 5
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-7
+description:
+ fc allows too old/new errors in range specification
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ echo line 5
+ fc -l 1 30
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ 4 echo line 4
+ 5 echo line 5
+ 6 fc -l 1 30
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-r-1
+description:
+ test -r flag in history
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ echo line 5
+ fc -l -r 2 4
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ 4 echo line 4
+ 3 echo line 3
+ 2 echo line 2
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-r-2
+description:
+ If first is newer than last, -r is implied.
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ echo line 5
+ fc -l 4 2
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ 4 echo line 4
+ 3 echo line 3
+ 2 echo line 2
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-list-r-3
+description:
+ If first is newer than last, -r is cancelled.
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2
+ echo line 3
+ echo line 4
+ echo line 5
+ fc -l -r 4 2
+expected-stdout:
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ 2 echo line 2
+ 3 echo line 3
+ 4 echo line 4
+expected-stderr-pattern:
+ /^X*$/
+---
+
+name: history-subst-1
+description:
+ Basic substitution
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ echo ghi jkl
+ fc -e - abc=AB 'echo a'
+expected-stdout:
+ abc def
+ ghi jkl
+ AB def
+expected-stderr-pattern:
+ /^X*echo AB def\nX*$/
+---
+
+name: history-subst-2
+description:
+ Does subst find previous command?
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ echo ghi jkl
+ fc -e - jkl=XYZQRT 'echo g'
+expected-stdout:
+ abc def
+ ghi jkl
+ ghi XYZQRT
+expected-stderr-pattern:
+ /^X*echo ghi XYZQRT\nX*$/
+---
+
+name: history-subst-3
+description:
+ Does subst find previous command when no arguments given
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ echo ghi jkl
+ fc -e - jkl=XYZQRT
+expected-stdout:
+ abc def
+ ghi jkl
+ ghi XYZQRT
+expected-stderr-pattern:
+ /^X*echo ghi XYZQRT\nX*$/
+---
+
+name: history-subst-4
+description:
+ Global substitutions work
+ (ksh88 and ksh93 do not have -g option)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def asjj sadjhasdjh asdjhasd
+ fc -e - -g a=FooBAR
+expected-stdout:
+ abc def asjj sadjhasdjh asdjhasd
+ FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd
+expected-stderr-pattern:
+ /^X*echo FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd\nX*$/
+---
+
+name: history-subst-5
+description:
+ Make sure searches don't find current (fc) command
+ (ksh88/ksh93 don't have the ? prefix thing so they fail this test)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ echo ghi jkl
+ fc -e - abc=AB \?abc
+expected-stdout:
+ abc def
+ ghi jkl
+ AB def
+expected-stderr-pattern:
+ /^X*echo AB def\nX*$/
+---
+
+name: history-ed-1
+description:
+ Basic (ed) editing works (assumes you have generic ed editor
+ that prints no prompts).
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ fc echo
+ s/abc/FOOBAR/
+ w
+ q
+expected-stdout:
+ abc def
+ 13
+ 16
+ FOOBAR def
+expected-stderr-pattern:
+ /^X*echo FOOBAR def\nX*$/
+---
+
+name: history-ed-2
+description:
+ Correct command is edited when number given
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo line 1
+ echo line 2 is here
+ echo line 3
+ echo line 4
+ fc 2
+ s/is here/is changed/
+ w
+ q
+expected-stdout:
+ line 1
+ line 2 is here
+ line 3
+ line 4
+ 20
+ 23
+ line 2 is changed
+expected-stderr-pattern:
+ /^X*echo line 2 is changed\nX*$/
+---
+
+name: history-ed-3
+description:
+ Newly created multi line commands show up as single command
+ in history.
+ (NOTE: will fail if using COMPLEX HISTORY compile time option)
+ (ksh88 fails 'cause it lists the fc command)
+arguments: !-i!
+env-setup: !ENV=./Env!HISTFILE=hist.file!
+perl-setup: system("echo PS1=X > Env");
+stdin:
+ echo abc def
+ fc echo
+ s/abc/FOOBAR/
+ $a
+ echo a new line
+ .
+ w
+ q
+ fc -l
+expected-stdout:
+ abc def
+ 13
+ 32
+ FOOBAR def
+ a new line
+ 1 echo abc def
+ 2 echo FOOBAR def
+ echo a new line
+expected-stderr-pattern:
+ /^X*echo FOOBAR def\necho a new line\nX*$/
+---
diff --git a/bin/ksh/tests/ifs.t b/bin/ksh/tests/ifs.t
new file mode 100644
index 00000000000..a927aa301fc
--- /dev/null
+++ b/bin/ksh/tests/ifs.t
@@ -0,0 +1,162 @@
+name: IFS-space-1
+description:
+ Simple test, default IFS
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ set -- A B C
+ showargs 1 $*
+ showargs 2 "$*"
+ showargs 3 $@
+ showargs 4 "$@"
+expected-stdout:
+ <1> <A> <B> <C>
+ <2> <A B C>
+ <3> <A> <B> <C>
+ <4> <A> <B> <C>
+---
+
+name: IFS-colon-1
+description:
+ Simple test, IFS=:
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS=:
+ set -- A B C
+ showargs 1 $*
+ showargs 2 "$*"
+ showargs 3 $@
+ showargs 4 "$@"
+expected-stdout:
+ <1> <A> <B> <C>
+ <2> <A:B:C>
+ <3> <A> <B> <C>
+ <4> <A> <B> <C>
+---
+
+name: IFS-null-1
+description:
+ Simple test, IFS=""
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS=""
+ set -- A B C
+ showargs 1 $*
+ showargs 2 "$*"
+ showargs 3 $@
+ showargs 4 "$@"
+expected-stdout:
+ <1> <A B C>
+ <2> <ABC>
+ <3> <A B C>
+ <4> <A B C>
+---
+
+name: IFS-space-colon-1
+description:
+ Simple test, IFS=<white-space>:
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="IFS:"
+ set --
+ showargs 1 $*
+ showargs 2 "$*"
+ showargs 3 $@
+ showargs 4 "$@"
+ showargs 5 : "$@"
+expected-stdout:
+ <1>
+ <2> <>
+ <3>
+ <4>
+ <5> <:>
+---
+
+name: IFS-space-colon-2
+description:
+ Simple test, IFS=<white-space>:
+ At&t ksh fails this, POSIX says the test is correct.
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="IFS:"
+ set --
+ showargs :"$@"
+expected-stdout:
+ <:>
+---
+
+name: IFS-space-colon-3
+description:
+ Simple test, IFS=<white-space>:
+ pdksh fails both of these tests
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="IFS:"
+ x=
+ set --
+ showargs "$x$@"
+ showargs "$@$x"
+expected-fail: yes
+expected-stdout:
+ <>
+ <>
+---
+
+name: IFS-space-colon-4
+description:
+ Simple test, IFS=<white-space>:
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="IFS:"
+ set --
+ showargs "$@$@"
+expected-stdout:
+
+---
+
+name: IFS-space-colon-5
+description:
+ Simple test, IFS=<white-space>:
+ Don't know what POSIX thinks of this. at&t ksh does not do this.
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="IFS:"
+ set --
+ showargs "${@:-}"
+expected-stdout:
+ <>
+---
+
+name: IFS-subst-1
+description:
+ Simple test, IFS=<white-space>:
+stdin:
+ showargs() { for i; do echo -n " <$i>"; done; echo; }
+ IFS="$IFS:"
+ x=":b: :"
+ echo -n '1:'; for i in $x ; do echo -n " [$i]" ; done ; echo
+ echo -n '2:'; for i in :b:: ; do echo -n " [$i]" ; done ; echo
+ showargs 3 $x
+ showargs 4 :b::
+ x="a:b:"
+ echo -n '5:'; for i in $x ; do echo -n " [$i]" ; done ; echo
+ showargs 6 $x
+ x="a::c"
+ echo -n '7:'; for i in $x ; do echo -n " [$i]" ; done ; echo
+ showargs 8 $x
+ echo -n '9:'; for i in ${FOO-`echo -n h:i`th:ere} ; do echo -n " [$i]" ; done ; echo
+ showargs 10 ${FOO-`echo -n h:i`th:ere}
+ showargs 11 "${FOO-`echo -n h:i`th:ere}"
+expected-stdout:
+ 1: [] [b] [] []
+ 2: [:b::]
+ <3> <> <b> <> <>
+ <4> <:b::>
+ 5: [a] [b] []
+ <6> <a> <b> <>
+ 7: [a] [] [c]
+ <8> <a> <> <c>
+ 9: [h] [ith] [ere]
+ <10> <h> <ith> <ere>
+ <11> <h:ith:ere>
+---
+
diff --git a/bin/ksh/tests/integer.t b/bin/ksh/tests/integer.t
new file mode 100644
index 00000000000..7e39612b3ff
--- /dev/null
+++ b/bin/ksh/tests/integer.t
@@ -0,0 +1,218 @@
+name: integer-base-err-1
+description:
+ Can't have 0 base (causes shell to exit)
+expected-exit: e != 0
+stdin:
+ typeset -i i
+ i=3
+ i=0#4
+ echo $i
+expected-stderr-pattern:
+ /^.*:.*0#4.*\n$/
+---
+
+name: integer-base-err-2
+description:
+ Can't have multiple bases in a `constant' (causes shell to exit)
+ (ksh88 fails this test)
+expected-exit: e != 0
+stdin:
+ typeset -i i
+ i=3
+ i=2#110#11
+ echo $i
+expected-stderr-pattern:
+ /^.*:.*2#110#11.*\n$/
+---
+
+name: integer-base-err-3
+description:
+ Syntax errors in expressions and effects on bases
+ (interactive so errors don't cause exits)
+ (ksh88 fails this test - shell exits, even with -i)
+arguments: !-i!
+stdin:
+ PS1= # minimize prompt hassles
+ typeset -i4 a=10
+ typeset -i a=2+
+ echo $a
+ typeset -i4 a=10
+ typeset -i2 a=2+
+ echo $a
+expected-stderr-pattern:
+ /^([#\$] )?.*:.*2+.*\n.*:.*2+.*\n$/
+expected-stdout:
+ 4#22
+ 4#22
+---
+
+name: integer-base-err-4
+description:
+ Are invalid digits (according to base) errors?
+ (ksh93 fails this test)
+expected-exit: e != 0
+stdin:
+ typeset -i i;
+ i=3#4
+expected-stderr-pattern:
+ /^([#\$] )?.*:.*3#4.*\n$/
+---
+
+
+name: integer-base-1
+description:
+ Missing number after base is treated as 0.
+stdin:
+ typeset -i i
+ i=3
+ i=2#
+ echo $i
+expected-stdout:
+ 0
+---
+
+name: integer-base-2
+description:
+ Check `stickyness' of base in various situations
+stdin:
+ typeset -i i=8
+ echo $i
+ echo ---------- A
+ typeset -i4 j=8
+ echo $j
+ echo ---------- B
+ typeset -i k=8
+ typeset -i4 k=8
+ echo $k
+ echo ---------- C
+ typeset -i4 l
+ l=3#10
+ echo $l
+ echo ---------- D
+ typeset -i m
+ m=3#10
+ echo $m
+ echo ---------- E
+ n=2#11
+ typeset -i n
+ echo $n
+ n=10
+ echo $n
+ echo ---------- F
+ typeset -i8 o=12
+ typeset -i4 o
+ echo $o
+ echo ---------- G
+ typeset -i p
+ let p=8#12
+ echo $p
+expected-stdout:
+ 8
+ ---------- A
+ 4#20
+ ---------- B
+ 4#20
+ ---------- C
+ 4#3
+ ---------- D
+ 3#10
+ ---------- E
+ 2#11
+ 2#1010
+ ---------- F
+ 4#30
+ ---------- G
+ 8#12
+---
+
+name: integer-base-3
+description:
+ More base parsing (hmm doesn't test much..)
+stdin:
+ typeset -i aa
+ aa=1+12#10+2
+ echo $aa
+ typeset -i bb
+ bb=1+$aa
+ echo $bb
+ typeset -i bb
+ bb=$aa
+ echo $bb
+ typeset -i cc
+ cc=$aa
+ echo $cc
+expected-stdout:
+ 15
+ 16
+ 15
+ 15
+---
+
+name: integer-base-4
+description:
+ Check that things not declared as integers are not made integers,
+ also, check if base is not reset by -i with no arguments.
+ (ksh93 fails - prints 10#20 - go figure)
+stdin:
+ xx=20
+ let xx=10
+ typeset -i | grep '^xx='
+ typeset -i4 a=10
+ typeset -i a=20
+ echo $a
+expected-stdout:
+ 4#110
+---
+
+name: integer-base-5
+description:
+ More base stuff
+stdin:
+ typeset -i4 a=3#10
+ echo $a
+ echo --
+ typeset -i j=3
+ j=~3
+ echo $j
+ echo --
+ typeset -i k=1
+ x[k=k+1]=3
+ echo $k
+ echo --
+ typeset -i l
+ for l in 1 2+3 4; do echo $l; done
+expected-stdout:
+ 4#3
+ --
+ -4
+ --
+ 2
+ --
+ 1
+ 5
+ 4
+---
+
+name: integer-base-6
+description:
+ Even more base stuff
+ (ksh93 fails this test - prints 0)
+stdin:
+ typeset -i7 i
+ i=
+ echo $i
+expected-stdout:
+ 7#0
+---
+
+name: integer-base-7
+description:
+ Check that non-integer parameters don't get bases assigned
+stdin:
+ echo $(( zz = 8#100 ))
+ echo $zz
+expected-stdout:
+ 64
+ 64
+---
+
diff --git a/bin/ksh/tests/read.t b/bin/ksh/tests/read.t
new file mode 100644
index 00000000000..aced86adc32
--- /dev/null
+++ b/bin/ksh/tests/read.t
@@ -0,0 +1,56 @@
+#
+# To test:
+# POSIX:
+# - if no -r, \ is escape character
+# - \newline disappear
+# - \<IFS> -> don't break here
+# - \<anything-else> -> <anything-else>
+# - if -r, backslash is not special
+# - if stdin is tty and shell interactive
+# - prompt for continuation if \newline (prompt to stderr)
+# - a here-document isn't terminated after newline ????
+# - remaining vars set to empty string (not null)
+# - check field splitting
+# - left over fields and their seperators assigned to last var
+# - exit status is normally 0
+# - exit status is > 0 on eof
+# - exit status > 0 on error
+# - signals interrupt reads
+# extra:
+# - can't change read-only variables
+# - error if var name bogus
+# - set -o allexport effects read
+# ksh:
+# x check default variable: REPLY
+# - check -p, -s, -u options
+# - check var?prompt stuff
+# - "echo a b | read x y" sets x,y in parent shell (at&t)
+#
+name: read-IFS-1
+description:
+ Simple test, default IFS
+stdin:
+ echo "A B " > IN
+ unset x y z
+ read x y z < IN
+ echo 1: "x[$x] y[$y] z[$z]"
+ echo 1a: ${z-z not set}
+ read x < IN
+ echo 2: "x[$x]"
+expected-stdout:
+ 1: x[A] y[B] z[]
+ 1a:
+ 2: x[A B]
+---
+
+name: read-ksh-1
+description:
+ If no var specified, REPLY is used
+stdin:
+ echo "abc" > IN
+ read < IN
+ echo "[$REPLY]";
+expected-stdout:
+ [abc]
+---
+
diff --git a/bin/ksh/tests/regress.t b/bin/ksh/tests/regress.t
new file mode 100644
index 00000000000..95fe97b6b7c
--- /dev/null
+++ b/bin/ksh/tests/regress.t
@@ -0,0 +1,641 @@
+#
+# The first 39 of these tests are from the old Bugs script.
+#
+
+name: regression-1
+description:
+ Lex array code had problems with this.
+stdin:
+ echo foo[
+ n=bar
+ echo "hi[ $n ]=1"
+expected-stdout:
+ foo[
+ hi[ bar ]=1
+---
+
+
+name: regression-2
+description:
+ When PATH is set before running a command, the new path is
+ not used in doing the path search
+ $ echo echo hi > /tmp/q ; chmod a+rx /tmp/q
+ $ PATH=/tmp q
+ q: not found
+ $
+ in comexec() the two lines
+ while (*vp != NULL)
+ (void) typeset(*vp++, xxx, 0);
+ need to be moved out of the switch to before findcom() is
+ called - I don't know what this will break.
+stdin:
+ : ${PWD:-`pwd 2> /dev/null`}
+ : ${PWD:?"PWD not set - can't do test"}
+ mkdir Y
+ cat > Y/xxxscript << EOF
+ #!/bin/sh
+ echo hi
+ exit 0
+ EOF
+ chmod a+rx Y/xxxscript
+ PATH=$PWD/Y xxxscript
+ exit $?
+expected-stdout:
+ hi
+---
+
+
+#
+# 3. Sun OS 4.0.x (This seems to be a problem with sun's PENDIN not being done
+# properly)
+# sleep 5^J ls^J ls^J ls [only first ls runs]
+# vi ... ZZ (while waiting type) [some of the input gets eaten]
+# [not present in SunOS 4.1.x]
+#echo " [No automatic test for bug 3 - interactive]"
+
+
+#
+# 4. (fixed)
+#
+#echo " [Don't know what bug 4 was]"
+
+
+#
+# 5. Everywhere
+# File name completion (^X,*) does not mesh well with cd and
+# symbolic links. cd does path simplification wrt $PWD before
+# doing the actual chdir(), while file name completion does
+# not do the simplification. E.g., you are in directory A
+# which has a symbolic link to directory B, you create a file
+# called foobar and you then cd to the symlink to B, and type
+# $ echo ../foo^X
+# and the shell beeps at you. Would be more consistent to
+# do the completion after simplifing the `$PWD/..'.
+#echo " [No automatic test for bug 5 - interactive]"
+
+
+name: regression-6
+description:
+ Parsing of $(..) expressions is non-optimal. It is
+ impossible to have any parentheses inside the expression.
+ I.e.,
+ $ ksh -c 'echo $(echo \( )'
+ no closing quote
+ $ ksh -c 'echo $(echo "(" )'
+ no closing quote
+ $
+ The solution is to hack the parsing clode in lex.c, the
+ question is how to hack it: should any parentheses be
+ escaped by a backslash, or should recursive parsing be done
+ (so quotes could also be used to hide hem). The former is
+ easier, the later better...
+stdin:
+ echo $(echo \()
+expected-stdout:
+ (
+---
+
+
+#
+# 7. (fixed)
+#
+#echo " [Don't know what bug 7 was]"
+
+
+#
+# 8. Everywhere - NOT A BUG - this is what at&t ksh88 does
+# Strange typset -x behaviour in functions. The following function
+# does not set the environment variable BLAH outside the function:
+# function blah
+# {
+# typeset -x BLAH=foobar
+# }
+# This function does work:
+# function blah
+# { BLAH=foobar; export BLAH
+# }
+#echo ' [Bug 8 was bogus]'
+
+
+name: regression-9
+description:
+ Continue in a for loop does not work right:
+ for i in a b c ; do
+ if [ $i = b ] ; then
+ continue
+ fi
+ echo $i
+ done
+ Prints a forever...
+stdin:
+ first=yes
+ for i in a b c ; do
+ if [ $i = b ] ; then
+ if [ $first = no ] ; then
+ echo 'continue in for loop broken'
+ break # hope break isn't broken too :-)
+ fi
+ first=no
+ continue
+ fi
+ done
+ echo bye
+expected-stdout:
+ bye
+---
+
+
+name: regression-10
+description:
+ The following:
+ set -- `false`
+ echo $?
+ shoud not print 0. (according to /bin/sh, at&t ksh88, and the
+ getopt(1) man page - not according to POSIX)
+stdin:
+ set -- `false`
+ echo $?
+expected-stdout:
+ 1
+---
+
+
+name: regression-11
+description:
+ The following:
+ x=/foo/bar/blah
+ echo ${x##*/}
+ should echo blah but on some machines echos /foo/bar/blah.
+stdin:
+ x=/foo/bar/blah
+ echo ${x##*/}
+expected-stdout:
+ blah
+---
+
+
+name: regression-12
+description:
+ Both of the following echos produce the same output under sh/ksh.att:
+ #!/bin/sh
+ x="foo bar"
+ echo "`echo \"$x\"`"
+ echo "`echo "$x"`"
+ pdksh produces different output for the former (foo instead of foo\tbar)
+stdin:
+ x="foo bar"
+ echo "`echo \"$x\"`"
+ echo "`echo "$x"`"
+expected-stdout:
+ foo bar
+ foo bar
+---
+
+
+name: regression-13
+description:
+ The following command hangs forever:
+ $ (: ; cat /etc/termcap) | sleep 2
+ This is because the shell forks a shell to run the (..) command
+ and this shell has the pipe open. When the sleep dies, the cat
+ doesn't get a SIGPIPE 'cause a process (ie, the second shell)
+ still has the pipe open.
+
+ NOTE: this test provokes a bizarre bug in ksh93 (shell starts reading
+ commands from /etc/termcap..)
+time-limit: 4
+stdin:
+ echo A line of text that will be duplicated quite a number of times.> t1
+ cat t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 > t2
+ cat t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 > t1
+ cat t1 t1 t1 t1 > t2
+ (: ; cat t2) | sleep 1
+---
+
+
+name: regression-14
+description:
+ The command
+ $ (foobar) 2> /dev/null
+ generates no output under /bin/sh, but pdksh produces the error
+ foobar: not found
+ Also, the command
+ $ foobar 2> /dev/null
+ generates an error under /bin/sh and pdksh, but at&t ksh88 produces
+ no error (redirected to /dev/null).
+stdin:
+ (you/should/not/see/this/error/1) 2> /dev/null
+ you/should/not/see/this/error/2 2> /dev/null
+ true
+---
+
+
+name: regression-15
+description:
+ The command
+ $ whence foobar
+ generates a blank line under pdksh and sets the exit status to 0.
+ at&t ksh88 generates no output and sets the exit status to 1. Also,
+ the command
+ $ whence foobar cat
+ generates no output under at&t ksh88 (pdksh generates a blank line
+ and /bin/cat).
+stdin:
+ whence does/not/exist > /dev/null
+ echo 1: $?
+ echo 2: $(whence does/not/exist | wc -l)
+ echo 3: $(whence does/not/exist cat | wc -l)
+expected-stdout:
+ 1: 1
+ 2: 0
+ 3: 0
+---
+
+
+name: regression-16
+description:
+ ${var%%expr} seems to be broken in many places. On the mips
+ the commands
+ $ read line < /etc/passwd
+ $ echo $line
+ root:0:1:...
+ $ echo ${line%%:*}
+ root
+ $ echo $line
+ root
+ $
+ change the value of line. On sun4s & pas, the echo ${line%%:*} doesn't
+ work. Haven't checked elsewhere...
+script:
+ read x
+ y=$x
+ echo ${x%%:*}
+ echo $x
+stdin:
+ root:asdjhasdasjhs:0:1:Root:/:/bin/sh
+expected-stdout:
+ root
+ root:asdjhasdasjhs:0:1:Root:/:/bin/sh
+---
+
+
+name: regression-17
+description:
+ The command
+ . /foo/bar
+ should set the exit status to non-zero (sh and at&t ksh88 do).
+ XXX doting a non existant file is a fatal error for a script
+stdin:
+ . does/not/exist
+expected-exit: e != 0
+expected-stderr-pattern: /.?/
+---
+
+
+#
+# 18. Everywhere
+# In vi mode ^X (and *) can dump core:
+# $ ab[cd^XMemory fault (core dumped)
+#echo " [No automatic test for bug 18 - interactive]"
+
+
+name: regression-19
+description:
+ Both of the following echos should produce the same thing, but don't:
+ $ x=foo/bar
+ $ echo ${x%/*}
+ foo
+ $ echo "${x%/*}"
+ foo/bar
+stdin:
+ x=foo/bar
+ echo "${x%/*}"
+expected-stdout:
+ foo
+---
+
+
+#
+# 20. (same as 18)
+#
+
+
+name: regression-21
+description:
+ backslash does not work as expected in case labels:
+ $ x='-x'
+ $ case $x in
+ -\?) echo hi
+ esac
+ hi
+ $ x='-?'
+ $ case $x in
+ -\\?) echo hi
+ esac
+ hi
+ $
+stdin:
+ case -x in
+ -\?) echo fail
+ esac
+---
+
+
+name: regression-22
+description:
+ Quoting backquotes inside backquotes doesn't work:
+ $ echo `echo hi \`echo there\` folks`
+ asks for more info. sh and at&t ksh88 both echo
+ hi there folks
+stdin:
+ echo `echo hi \`echo there\` folks`
+expected-stdout:
+ hi there folks
+---
+
+
+name: regression-23
+description:
+ )) is not treated `correctly':
+ $ (echo hi ; (echo there ; echo folks))
+ missing ((
+ $
+ instead of (as sh and ksh.att)
+ $ (echo hi ; (echo there ; echo folks))
+ hi
+ there
+ folks
+ $
+stdin:
+ ( : ; ( : ; echo hi))
+expected-stdout:
+ hi
+---
+
+
+#
+# 24. strangeness with file name completion involving symlinks to nowhere
+# $ mkdir foo foo/bar
+# $ ln -s /stuff/junk foo/bar/xx
+# $ echo foo/*/xx 
+# (beep)
+# $
+#echo " [No automatic test for bug 24 - interactive]"
+
+
+name: regression-25
+description:
+ Check reading stdin in a while loop. The read should only read
+ a single line, not a whole stdio buffer; the cat should get
+ the rest.
+stdin:
+ (echo a; echo b) | while read x ; do
+ echo $x
+ cat > /dev/null
+ done
+expected-stdout:
+ a
+---
+
+
+name: regression-26
+description:
+ Check reading stdin in a while loop. The read should read both
+ lines, not just the first.
+script:
+ a=
+ while [ "$a" != xxx ] ; do
+ last=$x
+ read x
+ /bin/cat /dev/null | sed 's/x/y/'
+ a=x$a
+ done
+ echo $last
+stdin:
+ a
+ b
+expected-stdout:
+ b
+---
+
+
+name: regression-27
+description:
+ The command
+ . /does/not/exist
+ should cause a script to exit.
+stdin:
+ . does/not/exist
+ echo hi
+expected-exit: e != 0
+expected-stderr-pattern: /does\/not\/exist/
+---
+
+
+name: regression-28
+description:
+ variable assignements not detected well
+stdin:
+ a.x=1 echo hi
+expected-exit: e != 0
+expected-stderr-pattern: /a\.x=1/
+---
+
+
+name: regression-29
+description:
+ alias expansion different from at&t ksh88
+stdin:
+ alias a='for ' b='i in'
+ a b hi ; do echo $i ; done
+expected-stdout:
+ hi
+---
+
+
+name: regression-30
+description:
+ strange characters allowed inside ${...}
+stdin:
+ echo ${a{b}}
+expected-exit: e != 0
+expected-stderr-pattern: /.?/
+---
+
+
+name: regression-31
+description:
+ Does read handle partial lines correctly
+script:
+ a= ret=
+ while [ "$a" != xxx ] ; do
+ read x y z
+ ret=$?
+ a=x$a
+ done
+ echo "[$x]"
+ echo $ret
+stdin: !
+ a A aA
+ b B Bb
+ c
+expected-stdout:
+ [c]
+ 1
+---
+
+
+name: regression-32
+description:
+ Does read set variables to null at eof?
+script:
+ a=
+ while [ "$a" != xxx ] ; do
+ read x y z
+ a=x$a
+ done
+ echo 1: ${x-x not set} ${y-y not set} ${z-z not set}
+ echo 2: ${x:+x not null} ${y:+y not null} ${z:+z not null}
+stdin:
+ a A Aa
+ b B Bb
+expected-stdout:
+ 1:
+ 2:
+---
+
+
+name: regression-33
+description:
+ Does umask print a leading 0 when umask is 3 digits?
+stdin:
+ umask 222
+ umask
+expected-stdout:
+ 0222
+---
+
+
+#
+#
+# Does umask print a umask of 0 sanely?
+# There is lots of variety here (0, 00, 000, and 0000 have all been
+# seen in various shells...)
+#
+#echo ' [Bug 34 was bogus]'
+
+
+name: regression-35
+description:
+ Tempory files used for here-docs in functions get trashed after
+ the function is parsed (before it is executed)
+stdin:
+ f1() {
+ cat <<- EOF
+ F1
+ EOF
+ f2() {
+ cat <<- EOF
+ F2
+ EOF
+ }
+ }
+ f1
+ f2
+ unset -f f1
+ f2
+expected-stdout:
+ F1
+ F2
+ F2
+---
+
+
+name: regression-36
+description:
+ Command substitution breaks reading in while loop
+ (test from <sjg@void.zen.oz.au>)
+stdin:
+ (echo abcdef; echo; echo 123) |
+ while read line
+ do
+ # the following line breaks it
+ c=`echo $line | wc -c`
+ echo $c
+ done
+expected-stdout:
+ 7
+ 1
+ 4
+---
+
+
+name: regression-37
+description:
+ Machines with broken times() (reported by <sjg@void.zen.oz.au>)
+ time does not report correct real time
+stdin:
+ time sleep 1
+expected-stderr-pattern: !/^\s*0\.0[\s\d]+real|^\s*real[\s]+0+\.0/
+---
+
+
+name: regression-38
+description:
+ set -e doesn't ignore exit codes for if/while/until/&&/||/!.
+arguments: !-e!
+stdin:
+ if false; then echo hi ; fi
+ false || true
+ false && true
+ while false; do echo hi; done
+ echo ok
+expected-stdout:
+ ok
+---
+
+
+name: regression-39
+description:
+ set -e: errors in command substitutions aren't ignored
+ Not clear if they should be or not...
+expected-fail: yes
+arguments: !-e!
+stdin:
+ echo `false; echo hi`
+expected-stdout:
+ hi
+---
+
+name: regression-40
+description:
+ This used to cause a core dump
+env-setup: !RANDOM=12!
+stdin:
+ echo hi
+expected-stdout:
+ hi
+---
+
+name: regression-41
+description:
+ foo should be set to bar (should not be empty)
+stdin:
+ foo=`
+ echo bar`
+ echo "($foo)"
+expected-stdout:
+ (bar)
+---
+
+name: regression-42
+description:
+ Can't use command line assignments to assign readonly parameters.
+stdin:
+ foo=bar
+ readonly foo
+ foo=stuff env | grep '^foo'
+expected-exit: e != 0
+expected-stderr-pattern:
+ /.*read *only.*/
+---
diff --git a/bin/ksh/tests/th b/bin/ksh/tests/th
new file mode 100644
index 00000000000..496058ccd4e
--- /dev/null
+++ b/bin/ksh/tests/th
@@ -0,0 +1,813 @@
+#!/usr/local/bin/perl
+
+#
+# Test harness for pdksh tests.
+#
+# Example test:
+# name: a-test
+# description:
+# a test to show how tests are done
+# arguments: !-x!-f!
+# stdin:
+# echo -n *
+# false
+# expected-stdout: !
+# *
+# expected-stderr:
+# + echo -n *
+# + false
+# expected-exit: 1
+# ---
+# This runs the test-program (eg, pdksh) with the arguments -x and -f,
+# standard input is a file containing "echo hi*\nfalse\n". The program
+# is expected to produce "hi*" (no trailing newline) on standard output,
+# "+ echo hi*\n+false\n" on standard error, and an exit code of 1.
+#
+#
+# Format of test files:
+# - blank lines and lines starting with # are ignored
+# - a test file contains a series of tests
+# - a test is a series of tag:value pairs ended with a "---" line
+# (leading/trailing spaces are stripped from the first line of value)
+# - test tags are:
+# Tag Flag Description
+# ----- ---- -----------
+# name r The name of the test; should be unique
+# description m What test does
+# arguments M Arguments to pass to the program;
+# default is no arguments.
+# script m Value is written to a file which
+# is passed as an argument to the program
+# (after the arguments arguments)
+# stdin m Value is written to a file which is
+# used as standard-input for the program;
+# default is to use /dev/null.
+# perl-setup m Value is a perl script which is executed
+# just before the test is run. Try to
+# avoid using this...
+# perl-cleanup m Value is a perl script which is executed
+# just after the test is run. Try to
+# avoid using this...
+# env-setup M Value is a list of NAME=VALUE elements
+# which are put in the environment before
+# the test is run. If the =VALUE is
+# missing, NAME is removed from the
+# environment. Programs are run with
+# the following minimal environment:
+# USER, LOGNAME, HOME, PATH, SHELL
+# (values taken from the environment of
+# the test harness).
+# time-limit Time limit - the program is sent a
+# SIGKILL N seconds. Default is no
+# limit.
+# expected-fail `yes' if the test is expected to fail.
+# expected-exit expected exit code. Can be a number,
+# or a C expression using the variables
+# e, s and w (exit code, termination
+# signal, and status code).
+# expected-stdout m What the test should generate on stdout;
+# default is to expect no output.
+# expected-stdout-pattern m A perl pattern which matches the
+# expected output.
+# expected-stderr m What the test should generate on stderr;
+# default is to expect no output.
+# expected-stderr-pattern m A perl pattern which matches the
+# expected standard error.
+# Flag meanings:
+# r tag is required (eg, a test must have a name tag).
+# m value can be multiple lines. Lines must be prefixed with
+# a tab. If the value part of the initial tag:value line is
+# - empty: the initial blank line is stripped.
+# - a lone !: the last newline in the value is stripped;
+# M value can be multiple lines (prefixed by a tab) and consists
+# of multiple fields, delimited by a field seperator character.
+# The value must start and end with the f-s-c.
+#
+
+require 'signal.ph';
+require 'errno.ph';
+require 'getopts.pl';
+
+($prog = $0) =~ s#.*/##;
+
+$Usage = <<EOF ;
+Usage: $prog [-s test-set] [-p prog] [-v] test-name ...
+ -p p Use p as the program to test
+ -s s Read tests from file s; if s is a directory, it is recursively
+ scaned for test files (which end in .t).
+ -t t Use t as default time limit for tests (default is unlimited)
+ -v Verbose mode: print reason test failed.
+ test-name(s) specifies the name of the test(s) to run; if none are
+ specified, all tests are run.
+EOF
+
+#
+# r - required
+# m - can be multi-line
+# M - multi-line, but without trailing newline
+#
+%test_fields = (
+ 'name', 'r',
+ 'description', 'm',
+ 'arguments', 'M',
+ 'script', 'm',
+ 'stdin', 'm',
+ 'perl-setup', 'm',
+ 'perl-cleanup', 'm',
+ 'env-setup', 'M',
+ 'time-limit', '',
+ 'expected-fail', '',
+ 'expected-exit', '',
+ 'expected-stdout', 'm',
+ 'expected-stdout-pattern', 'm',
+ 'expected-stderr', 'm',
+ 'expected-stderr-pattern', 'm',
+ );
+# Filled in by read_test()
+%internal_test_fields = (
+ ':full-name', 1, # file:name
+ ':long-name', 1, # dir/file:lineno:name
+ );
+
+$temps = "/tmp/rts$$";
+$tempi = "/tmp/rti$$";
+$tempo = "/tmp/rto$$";
+$tempe = "/tmp/rte$$";
+$tempdir = "/tmp/rtd$$";
+
+$nfailed = 0;
+$nxfailed = 0;
+$npassed = 0;
+$nxpassed = 0;
+
+%known_tests = ();
+
+if (!&Getopts('p:s:t:v')) {
+ print STDERR $Usage;
+ exit 1;
+}
+
+die "$prog: no program specified (use -p)\n" if !defined $opt_p;
+die "$prog: no test set specified (use -s)\n" if !defined $opt_s;
+$test_prog = $opt_p;
+$verbose = defined $opt_v && $opt_v;
+$test_set = $opt_s;
+if (defined $opt_t) {
+ die "$prog: bad -t argument (should be number > 0): $opt_t\n"
+ if $opt_t !~ /^\d+$/ || $opt_t <= 0;
+ $default_time_limit = $opt_t;
+}
+
+# Note which tests are to be run.
+%do_test = ();
+grep($do_test{$_} = 1, @ARGV);
+$all_tests = @ARGV == 0;
+
+# Set up a very minimal environment
+%new_env = ();
+foreach $env (('USER', 'LOGNAME', 'HOME', 'PATH', 'SHELL')) {
+ $new_env{$env} = $ENV{$env} if defined $ENV{$env};
+}
+%old_env = %ENV;
+%ENV = %new_env;
+
+die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
+
+chop($pwd = `pwd 2> /dev/null`);
+die "$prog: couldn't get current working directory\n" if $pwd eq '';
+die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
+
+$test_prog = "$pwd/$test_prog" if substr($test_prog, 0, 1) ne '/';
+die "$prog: $test_prog is not executable - bye\n" if ! -x $test_prog;
+
+@trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP');
+@SIG{@trap_sigs} = ('cleanup_exit') x @trap_sigs;
+$child_kill_ok = 0;
+$SIG{'ALRM'} = 'catch_sigalrm';
+
+$| = 1;
+
+if (-d $test_set) {
+ $file_prefix_skip = length($test_set) + 1;
+ $ret = &process_test_dir($test_set);
+} else {
+ $file_prefix_skip = 0;
+ $ret = &process_test_file($test_set);
+}
+&cleanup_exit() if !defined $ret;
+
+$tot_failed = $nfailed + $nxfailed;
+$tot_passed = $npassed + $nxpassed;
+if ($tot_failed || $tot_passed) {
+ print "Total failed: $tot_failed";
+ print " ($nxfailed unexpected)" if $nxfailed;
+ print " (as expected)" if $nfailed && !$nxfailed;
+ print "\nTotal passed: $tot_passed";
+ print " ($nxpassed unexpected)" if $nxpassed;
+ print "\n";
+}
+
+&cleanup_exit('ok');
+
+sub
+cleanup_exit
+{
+ local($sig, $exitcode) = ('', 1);
+
+ if ($_[0] eq 'ok') {
+ $exitcode = 0;
+ } elsif ($_[0] ne '') {
+ $sig = $_[0];
+ }
+
+ unlink($tempi, $tempo, $tempe, $temps);
+ &scrub_dir($tempdir) if defined $tempdir;
+ rmdir($tempdir) if defined $tempdir;
+
+ if ($sig) {
+ $SIG{$sig} = 'DEFAULT';
+ kill $sig, $$;
+ return;
+ }
+ exit $exitcode;
+}
+
+sub
+catch_sigalrm
+{
+ $SIG{'ALRM'} = 'catch_sigalrm';
+ kill(9, $child_pid) if $child_kill_ok;
+ $child_killed = 1;
+}
+
+sub
+process_test_dir
+{
+ local($dir) = @_;
+ local($ret, $file);
+ local(@todo) = ();
+
+ if (!opendir(DIR, $dir)) {
+ print STDERR "$prog: can't open directory $dir - $!\n";
+ return undef;
+ }
+ while ($file = readdir(DIR)) {
+ push(@todo, $file) if $file =~ /^[^.].*\.t$/;
+ }
+ closedir(DIR);
+
+ foreach $file (@todo) {
+ $file = "$dir/$file";
+ if (-d $file) {
+ $ret = &process_test_dir($file);
+ } elsif (-f _) {
+ $ret = &process_test_file($file);
+ }
+ last if !defined $ret;
+ }
+
+ return $ret;
+}
+
+sub
+process_test_file
+{
+ local($file) = @_;
+ local($ret);
+
+ if (!open(IN, $file)) {
+ die "$prog: can't open $file - $!\n";
+ return undef;
+ }
+ while (1) {
+ $ret = &read_test($file, IN, *test);
+ last if !defined $ret || !$ret;
+ next if !$all_tests && !$do_test{$test{'name'}};
+ $ret = &run_test(*test);
+ last if !defined $ret;
+ }
+ close(IN);
+
+ return $ret;
+}
+
+sub
+run_test
+{
+ local(*test) = @_;
+ local($name) = $test{':full-name'};
+
+ #print "Running test $name...\n" if $verbose;
+
+ if (defined $test{'stdin'}) {
+ return undef if !&write_file($tempi, $test{'stdin'});
+ $ifile = $tempi;
+ } else {
+ $ifile = '/dev/null';
+ }
+
+ if (defined $test{'script'}) {
+ return undef if !&write_file($temps, $test{'script'});
+ }
+
+ return undef if !&scrub_dir($tempdir);
+
+ if (!chdir($tempdir)) {
+ print STDERR "$prog: couldn't cd to $tempdir - $!\n";
+ return undef;
+ }
+
+ if (defined $test{'perl-setup'}) {
+ eval $test{'perl-setup'};
+ if ($@ ne '') {
+ print STDERR "$prog:$test{':long-name'}: error running perl-setup - $@\n";
+ return undef;
+ }
+ }
+
+ $pid = fork;
+ if (!defined $pid) {
+ print STDERR "$prog: can't fork - $!\n";
+ return undef;
+ }
+ if (!$pid) {
+ @SIG{@trap_sigs} = ('DEFAULT') x @trap_sigs;
+ $SIG{'ALRM'} = 'DEFAULT';
+ if (defined $test{'env-setup'}) {
+ local($var, $val, $i);
+
+ foreach $var (split(substr($test{'env-setup'}, 0, 1),
+ $test{'env-setup'}))
+ {
+ $i = index($var, '=');
+ next if $i == 0 || $var eq '';
+ if ($i < 0) {
+ delete $ENV{$var};
+ } else {
+ $ENV{substr($var, 0, $i)} = substr($var, $i + 1);
+ }
+ }
+ }
+ if (!open(STDIN, "< $ifile")) {
+ print STDERR "$prog: couldn't open $ifile in child - $!\n";
+ kill('TERM', $$);
+ }
+ if (!open(STDOUT, "> $tempo")) {
+ print STDERR "$prog: couldn't open $tempo in child - $!\n";
+ kill('TERM', $$);
+ }
+ if (!open(STDERR, "> $tempe")) {
+ print STDOUT "$prog: couldn't open $tempe in child - $!\n";
+ kill('TERM', $$);
+ }
+ @argv = ($test_prog);
+ if (defined $test{'arguments'}) {
+ push(@argv,
+ split(substr($test{'arguments'}, 0, 1),
+ substr($test{'arguments'}, 1)));
+ }
+ push(@argv, $temps) if defined $test{'script'};
+ exec(@argv);
+ print STDERR "$prog: couldn't execute $test_prog - $!\n";
+ kill('TERM', $$);
+ exit(95);
+ }
+ $child_pid = $pid;
+ $child_killed = 0;
+ $child_kill_ok = 1;
+ alarm($test{'time-limit'}) if defined $test{'time-limit'};
+ while (1) {
+ $xpid = waitpid($pid, 0);
+ $child_kill_ok = 0;
+ if ($xpid < 0) {
+ next if $! == &EINTR;
+ print STDERR "$prog: error waiting for child - $!\n";
+ return undef;
+ }
+ last;
+ }
+ $status = $?;
+ alarm(0) if defined $test{'time-limit'};
+
+ $failed = 0;
+ $why = '';
+
+ if ($child_killed) {
+ $failed = 1;
+ $why .= "\ttest timed out (limit of $test{'time-limit'} seconds)\n";
+ }
+
+ $ret = &eval_exit($test{'long-name'}, $status, $test{'expected-exit'});
+ return undef if !defined $ret;
+ if (!$ret) {
+ local($expl);
+
+ $failed = 1;
+ if (($status & 0xff) == 0x7f) {
+ $expl = "stopped";
+ } elsif (($status & 0xff)) {
+ $expl = "signal " . ($status & 0x7f);
+ } else {
+ $expl = "exit-code " . (($status >> 8) & 0xff);
+ }
+ $why .=
+ "\tunexpected exit status $status ($expl), expected $test{'expected-exit'}\n";
+ }
+
+ $tmp = &check_output($test{'long-name'}, $tempo, 'stdout',
+ $test{'expected-stdout'}, $test{'expected-stdout-pattern'});
+ return undef if !defined $tmp;
+ if ($tmp ne '') {
+ $failed = 1;
+ $why .= $tmp;
+ }
+
+ $tmp = &check_output($test{'long-name'}, $tempe, 'stderr',
+ $test{'expected-stderr'}, $test{'expected-stderr-pattern'});
+ return undef if !defined $tmp;
+ if ($tmp ne '') {
+ $failed = 1;
+ $why .= $tmp;
+ }
+
+ if (defined $test{'perl-cleanup'}) {
+ eval $test{'perl-cleanup'};
+ if ($@ ne '') {
+ print STDERR "$prog:$test{':long-name'}: error running perl-cleanup - $@\n";
+ return undef;
+ }
+ }
+
+ if (!chdir($pwd)) {
+ print STDERR "$prog: couldn't cd to $pwd - $!\n";
+ return undef;
+ }
+
+ if ($failed) {
+ if (!$test{'expected-fail'}) {
+ print "FAIL $name\n";
+ $nxfailed++;
+ } else {
+ print "fail $name (as expected)\n";
+ $nfailed++;
+ }
+ $why = "\tDescription"
+ . &wrap_lines($test{'description'}, " (missing)\n")
+ . $why;
+ } elsif ($test{'expected-fail'}) {
+ print "PASS $name (unexpectedly)\n";
+ $nxpassed++;
+ } else {
+ print "pass $name\n";
+ $npassed++;
+ }
+ print $why if $verbose;
+ return 0;
+}
+
+sub
+scrub_dir
+{
+ local($dir) = @_;
+ local(@todo) = ();
+ local($file);
+
+ if (!opendir(DIR, $dir)) {
+ print STDERR "$prog: couldn't open direcotry $dir - $!\n";
+ return undef;
+ }
+ while ($file = readdir(DIR)) {
+ push(@todo, $file) if $file ne '.' && $file ne '..';
+ }
+ closedir(DIR);
+ foreach $file (@todo) {
+ $file = "$dir/$file";
+ if (-d $file) {
+ return undef if !&scrub_dir($file);
+ if (!rmdir($file)) {
+ print STDERR "$prog: couldn't rmdir $file - $!\n";
+ return undef;
+ }
+ } else {
+ if (!unlink($file)) {
+ print STDERR "$prog: couldn't unlink $file - $!\n";
+ return undef;
+ }
+ }
+ }
+ return 1;
+}
+
+sub
+write_file
+{
+ local($file, $str) = @_;
+
+ if (!open(TEMP, "> $file")) {
+ print STDERR "$prog: can't open $file - $!\n";
+ return undef;
+ }
+ print TEMP $str;
+ if (!close(TEMP)) {
+ print STDERR "$prog: error writing $file - $!\n";
+ return undef;
+ }
+ return 1;
+}
+
+sub
+check_output
+{
+ local($name, $file, $what, $expect, $expect_pat) = @_;
+ local($got) = '';
+ local($why) = '';
+ local($ret);
+
+ if (!open(TEMP, "< $file")) {
+ print STDERR "$prog:$name($what): couldn't open $file after running program - $!\n";
+ return undef;
+ }
+ while (<TEMP>) {
+ $got .= $_;
+ }
+ close(TEMP);
+ if (defined $expect_pat) {
+ $_ = $got;
+ $ret = eval "$expect_pat";
+ if ($@ ne '') {
+ print STDERR "$prog:$name($what): error evaluating $what pattern: $expect_pat - $@\n";
+ return undef;
+ }
+ if (!$ret) {
+ $why = "\tunexpected $what - wanted pattern";
+ $why .= &wrap_lines($expect_pat);
+ $why .= "\tgot";
+ $why .= &wrap_lines($got);
+ }
+ } else {
+ $expect = '' if !defined $expect;
+ if ($got ne $expect) {
+ $why .= "\tunexpected $what - " . &first_diff($expect, $got) . "\n";
+ $why .= "\twanted";
+ $why .= &wrap_lines($expect);
+ $why .= "\tgot";
+ $why .= &wrap_lines($got);
+ }
+ }
+ return $why;
+}
+
+sub
+wrap_lines
+{
+ local($str, $empty) = @_;
+ local($nonl) = substr($str, -1, 1) ne "\n";
+
+ return (defined $empty ? $empty : " nothing\n") if $str eq '';
+ substr($str, 0, 0) = ":\n";
+ $str =~ s/\n/\n\t\t/g;
+ if ($nonl) {
+ $str .= "\n\t[incomplete last line]\n";
+ } else {
+ chop($str);
+ chop($str);
+ }
+ return $str;
+}
+
+sub
+first_diff
+{
+ local($exp, $got) = @_;
+ local($lineno, $char) = (1, 1);
+ local($i, $len);
+ local($ce, $cg);
+
+ $len = length($exp);
+ if ($len != length($got)) {
+ if ($len < length($got)) {
+ if (substr($got, 0, $len) eq $exp) {
+ return "got too much output";
+ }
+ } elsif (substr($exp, 0, $len) eq $got) {
+ return "got too little output";
+ }
+ $len = length($got);
+ }
+ for ($i = 0; $i < $len; $i++) {
+ $ce = substr($exp, $i, 1);
+ $cg = substr($got, $i, 1);
+ last if $ce ne $cg;
+ $char++;
+ if ($ce eq "\n") {
+ $lineno++;
+ $char = 1;
+ }
+ }
+ return "first difference: line $lineno, char $char"
+}
+
+sub
+eval_exit
+{
+ local($name, $status, $expect) = @_;
+ local($expr);
+ local($w, $e, $s) = ($status, ($status >> 8) & 0xff, $status & 0x7f);
+
+ $e = -1000 if $status & 0xff;
+ $s = -1000 if $s == 0x7f;
+ if (!defined $expect) {
+ $expr = '$w == 0';
+ } elsif ($expect =~ /^(|-)\d+$/) {
+ $expr = "\$e == $expect";
+ } else {
+ $expr = $expect;
+ $expr =~ s/\b([wse])\b/\$$1/g;
+ $expr =~ s/\b(SIG[A-Z0-9]+)\b/&$1/g;
+ }
+ $w = eval $expr;
+ if ($@ ne '') {
+ print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $expect ($@)\n";
+ return undef;
+ }
+ return $w;
+}
+
+sub
+read_test
+{
+ local($file, $in, *test) = @_;
+ local($field, $val, $flags, $do_chop, $need_redo, $start_lineno);
+
+ %test = ();
+ while (<$in>) {
+ next if /^\s*$/;
+ next if /^ *#/;
+ last if /^\s*---\s*$/;
+ $start_lineno = $. if !defined $start_lineno;
+ if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) {
+ print STDERR "$prog:$file:$.: unrecognized line\n";
+ return undef;
+ }
+ ($field, $val) = ($1, $2);
+ if (defined $test{$field}) {
+ print STDERR "$prog:$file:$.: multiple \"$field\" fields\n";
+ return undef;
+ }
+ $flags = $test_fields{$field};
+ if (!defined $flags) {
+ print STDERR "$prog:$file:$.: unrecognized field \"$field\"\n";
+ return undef;
+ }
+ $do_chop = $flags !~ /m/;
+ $need_redo = 0;
+ if ($val eq '' || $val eq '!') {
+ if ($flags =~ /[Mm]/) {
+ $do_chop = 1 if $val eq '!';
+ $val = '';
+ while (<$in>) {
+ last if !/^\t/;
+ $val .= $';
+ }
+ chop $val if $do_chop;
+ $do_chop = 1;
+ $need_redo = 1;
+ } elsif ($val eq '') {
+ print STDERR
+ "$prog:$file:$.: no value given for field \"$field\"\n";
+ return undef;
+ }
+ }
+ $val .= "\n" if !$do_chop;
+ $test{$field} = $val;
+ redo if $need_redo;
+ }
+ if ($_ eq '') {
+ if (%test) {
+ print STDERR
+ "$prog:$file:$start_lineno: end-of-file while reading test\n";
+ return undef;
+ }
+ return 0;
+ }
+
+ while (($field, $val) = each %test_fields) {
+ if ($val =~ /r/ && !defined $test{$field}) {
+ print STDERR
+ "$prog:$file:$start_lineno: required field \"$field\" missing\n";
+ return undef;
+ }
+ }
+
+ $test{':full-name'} = substr($file, $file_prefix_skip) . ":$test{'name'}";
+ $test{':long-name'} = "$file:$start_lineno:$test{'name'}";
+
+ # Syntax check on specific fields
+ if (defined $test{'expected-fail'}) {
+ if ($test{'expected-fail'} !~ /^(yes|no)$/) {
+ print STDERR
+ "$prog:$test{':long-name'}: bad value for expected-fail field\n";
+ return undef;
+ }
+ $test{'expected-fail'} = $1 eq 'yes';
+ } else {
+ $test{'expected-fail'} = 0;
+ }
+ if (defined $test{'arguments'}) {
+ local($firstc) = substr($test{'arguments'}, 0, 1);
+
+ if (substr($test{'arguments'}, -1, 1) ne $firstc) {
+ print STDERR "$prog:$test{':long-name'}: arguments field doesn't start and end with the same character\n";
+ return undef;
+ }
+ }
+ if (defined $test{'env-setup'}) {
+ local($firstc) = substr($test{'env-setup'}, 0, 1);
+
+ if (substr($test{'env-setup'}, -1, 1) ne $firstc) {
+ print STDERR "$prog:$test{':long-name'}: env-setup field doesn't start and end with the same character\n";
+ return undef;
+ }
+ }
+ if (defined $test{'expected-exit'}) {
+ local($val) = $test{'expected-exit'};
+
+ if ($val =~ /^(|-)\d+$/) {
+ if ($val < 0 || $val > 255) {
+ print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n";
+ return undef;
+ }
+ } elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z0-9]+\b)+$/) {
+ print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n";
+ return undef;
+ }
+ } else {
+ $test{'expected-exit'} = 0;
+ }
+ if (defined $test{'expected-stdout'}
+ && defined $test{'expected-stdout-pattern'})
+ {
+ print STDERR "$prog:$test{':long-name'}: can't use both expected-stdout and expected-stdout-pattern\n";
+ return undef;
+ }
+ if (defined $test{'expected-stderr'}
+ && defined $test{'expected-stderr-pattern'})
+ {
+ print STDERR "$prog:$test{':long-name'}: can't use both expected-stderr and expected-stderr-pattern\n";
+ return undef;
+ }
+ if (defined $test{'time-limit'}) {
+ if ($test{'time-limit'} !~ /^\d+$/ || $test{'time-limit'} == 0) {
+ print STDERR
+ "$prog:$test{':long-name'}: bad value for time-limit field\n";
+ return undef;
+ }
+ } elsif (defined $default_time_limit) {
+ $test{'time-limit'} = $default_time_limit;
+ }
+
+ if (defined $known_tests{$test{'name'}}) {
+ print STDERR "$prog:$test{':long-name'}: warning: duplicate test name ${test{'name'}}\n";
+ }
+ $known_tests{$test{'name'}} = 1;
+
+ return 1;
+}
+
+sub
+touch
+{
+ local(@files) = @_;
+ local($file);
+
+ foreach $file (@files) {
+ if (!open(T, "> $file")) {
+ die "Couldn't touch $file\n";
+ }
+ close(T);
+ }
+ return 1;
+}
+
+sub
+tty_msg
+{
+ local($msg) = @_;
+
+ open(TTY, "> /dev/tty") || return 0;
+ print TTY $msg;
+ close(TTY);
+ return 1;
+}
+
+sub
+never_called_funcs
+{
+ return 0;
+ &tty_msg("hi\n");
+ &touch("/tmp/foo");
+ &never_called_funcs();
+ &catch_sigalrm();
+ $old_env{'foo'} = 'bar';
+ $internal_test_fields{'foo'} = 'bar';
+}
diff --git a/bin/ksh/tests/th.sh b/bin/ksh/tests/th.sh
new file mode 100644
index 00000000000..6e40c19dcf9
--- /dev/null
+++ b/bin/ksh/tests/th.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+#
+# Simple script to find perl and run it
+#
+
+IFS=:$IFS
+perl=
+for i in $PATH; do
+ [ X"$i" = X ] && i=.
+ for j in perl perl4 perl5 ; do
+ [ -x "$i/$j" ] && perl=$i/$j && break 2
+ done
+done
+
+[ X"$perl" = X ] && {
+ echo "$0: can't find perl - bye\n" 1>&2
+ exit 1
+ }
+
+exec $perl "$@"
diff --git a/bin/ksh/tests/unclass1.t b/bin/ksh/tests/unclass1.t
new file mode 100644
index 00000000000..2e3e88791bf
--- /dev/null
+++ b/bin/ksh/tests/unclass1.t
@@ -0,0 +1,97 @@
+name: xxx-quoted-newline-1
+description:
+ Check that \<newline> works inside of ${}
+stdin:
+ abc=2
+ echo ${ab\
+ c}
+expected-stdout:
+ 2
+---
+
+name: xxx-quoted-newline-2
+description:
+ Check that \<newline> works at the start of a here document
+stdin:
+ cat << EO\
+ F
+ hi
+ EOF
+expected-stdout:
+ hi
+---
+
+name: xxx-quoted-newline-3
+description:
+ Check that \<newline> works at the end of a here document
+stdin:
+ cat << EOF
+ hi
+ EO\
+ F
+expected-stdout:
+ hi
+---
+
+name: xxx-multi-assignment-cmd
+description:
+ Check that assignments in a command affect subsequent assignments
+ in the same command
+stdin:
+ FOO=abc
+ FOO=123 BAR=$FOO
+ echo $BAR
+expected-stdout:
+ 123
+---
+
+name: xxx-exec-environment-1
+description:
+ Check to see if exec sets it's environment correctly
+stdin:
+ FOO=bar exec printenv
+expected-stdout-pattern:
+ /(^|.*\n)FOO=bar\n/
+---
+
+name: xxx-exec-environment-2
+description:
+ Check to make sure exec doesn't change environment if a program
+ isn't exec-ed
+stdin:
+ printenv > bar1
+ FOO=bar exec; printenv > bar2
+ cmp -s bar1 bar2
+---
+
+name: xxx-what-do-you-call-this-1
+stdin:
+ echo "${foo:-"a"}*"
+expected-stdout:
+ a*
+---
+
+name: xxx-prefix-strip-1
+stdin:
+ foo='a cdef'
+ echo ${foo#a c}
+expected-stdout:
+ def
+---
+
+name: xxx-prefix-strip-2
+stdin:
+ set a c
+ x='a cdef'
+ echo ${x#$*}
+expected-stdout:
+ def
+---
+
+name: xxx-variable-syntax-1
+stdin:
+ echo ${:}
+expected-stderr-pattern:
+ /bad substitution/
+expected-exit: 1
+---
diff --git a/bin/ksh/tests/unclass2.t b/bin/ksh/tests/unclass2.t
new file mode 100644
index 00000000000..d9e14822e06
--- /dev/null
+++ b/bin/ksh/tests/unclass2.t
@@ -0,0 +1,166 @@
+name: xxx-subsitution-eval-order
+description:
+ Check order of evaluation of expressions
+stdin:
+ i=1 x= y=
+ set -A A abc def GHI j G k
+ echo ${A[x=(i+=1)]#${A[y=(i+=2)]}}
+ echo $x $y
+expected-stdout:
+ HI
+ 2 4
+---
+
+name: xxx-set-option-1
+description:
+ Check option parsing in set
+stdin:
+ set -A -vs A 1 3 2
+ echo ${A[*]}
+expected-stderr:
+ echo ${A[*]}
+expected-stdout:
+ 1 2 3
+---
+
+name: xxx-exec-1
+description:
+ Check that exec exits for built-ins
+arguments: !-i!
+stdin:
+ exec print hi
+ echo still herre
+expected-stdout:
+ hi
+expected-stderr-pattern: /.*/
+---
+
+name: xxx-while-1
+description:
+ Check the return value of while loops
+ XXX need to do same for for/select/until loops
+stdin:
+ i=x
+ while [ $i != xxx ] ; do
+ i=x$i
+ if [ $i = xxx ] ; then
+ false
+ continue
+ fi
+ done
+ echo loop1=$?
+
+ i=x
+ while [ $i != xxx ] ; do
+ i=x$i
+ if [ $i = xxx ] ; then
+ false
+ break
+ fi
+ done
+ echo loop2=$?
+
+ i=x
+ while [ $i != xxx ] ; do
+ i=x$i
+ false
+ done
+ echo loop3=$?
+expected-stdout:
+ loop1=0
+ loop2=0
+ loop3=1
+---
+
+name: xxx-status-1
+description:
+ Check that blank lines don't clear $?
+arguments: !-i!
+stdin:
+ (exit 1)
+ echo $?
+ (exit 1)
+
+ echo $?
+ true
+expected-stdout:
+ 1
+ 1
+expected-stderr-pattern: /.*/
+---
+
+name: xxx-status-2
+description:
+ Check that $? is preserved in subshells, includes, traps.
+stdin:
+ (exit 1)
+
+ echo blank: $?
+
+ (exit 2)
+ (echo subshell: $?)
+
+ echo 'echo include: $?' > foo
+ (exit 3)
+ . ./foo
+
+ trap 'echo trap: $?' ERR
+ (exit 4)
+ echo exit: $?
+expected-stdout:
+ blank: 1
+ subshell: 2
+ include: 3
+ trap: 4
+ exit: 4
+---
+
+name: xxx-clean-chars-1
+description:
+ Check MAGIC character is stuffed correctly
+stdin:
+ echo `echo [£`
+expected-stdout:
+ [£
+---
+
+name: xxx-param-subst-qmark-1
+description:
+ Check suppresion of error message with null string. According to
+ POSIX, it shouldn't print the error as `word' isn't ommitted.
+stdin:
+ unset foo
+ x=
+ echo x${foo?$x}
+expected-exit: 1
+expected-fail: yes
+expected-stderr-pattern: !/not set/
+---
+
+name: xxx-param-_-1
+description:
+ Check c flag is set.
+arguments: !-c!echo "[$-]"!
+expected-stdout-pattern: /^\[.*c.*\]$/
+---
+
+name: env-prompt
+description:
+ Check that prompt not printed when processing ENV
+env-setup: !ENV=./foo!
+perl-setup:
+ system("cat > foo << EOF
+ XXX=12
+ PS1='X '
+ false && echo hmmm
+ EOF
+ ");
+arguments: !-i!
+stdin:
+ echo hi${XXX}there
+expected-stdout:
+ hi12there
+expected-stderr: !
+ X X
+---
+
diff --git a/bin/ksh/tests/version.t b/bin/ksh/tests/version.t
new file mode 100644
index 00000000000..aed94d01760
--- /dev/null
+++ b/bin/ksh/tests/version.t
@@ -0,0 +1,8 @@
+name: version-1
+description:
+ Check version of shell.
+stdin:
+ echo $KSH_VERSION
+expected-stdout:
+ @(#)PD KSH v5.2.7 96/06/04
+---