summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/pkg/manifests/system-test-libctest.mf37
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run2
-rw-r--r--usr/src/test/libc-tests/tests/regex/Makefile53
-rw-r--r--usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE41
-rw-r--r--usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE.descrip2
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/anchor.in33
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/backref.in21
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/basic.dat216
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/basic.in5
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/basic.out0
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/bracket.in55
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/c_comments.in17
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/categorize.dat62
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/categorize.out13
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/complex.in23
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/error.in30
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/forcedassoc.dat30
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/forcedassoc.out8
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/leftassoc.dat16
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/leftassoc.out12
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/meta.in21
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/nospec.in7
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/nullsubexpr.dat73
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/nullsubexpr.out32
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/paren.in19
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/regress.in9
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/repet_bounded.in58
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/repet_multi.in22
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/repet_ordinary.in10
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/repetition.dat140
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/repetition.out37
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/rightassoc.dat16
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/rightassoc.out0
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/startend.in9
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/subexp.in57
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/subtle.in21
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/word_bound.in13
-rw-r--r--usr/src/test/libc-tests/tests/regex/data/zero.in7
-rw-r--r--usr/src/test/libc-tests/tests/regex/main.c514
-rw-r--r--usr/src/test/libc-tests/tests/regex/regex_test.sh (renamed from usr/src/test/libc-tests/tests/regex/t_regex.sh)15
-rw-r--r--usr/src/test/libc-tests/tests/regex/split.c168
-rw-r--r--usr/src/test/libc-tests/tests/regex/test_regex.h39
-rw-r--r--usr/src/test/libc-tests/tests/regex/testregex.c2286
43 files changed, 3005 insertions, 1244 deletions
diff --git a/usr/src/pkg/manifests/system-test-libctest.mf b/usr/src/pkg/manifests/system-test-libctest.mf
index bc198602a7..32cb761128 100644
--- a/usr/src/pkg/manifests/system-test-libctest.mf
+++ b/usr/src/pkg/manifests/system-test-libctest.mf
@@ -128,27 +128,22 @@ file path=opt/libc-tests/tests/random/inz_region mode=0555
file path=opt/libc-tests/tests/random/inz_split mode=0555
file path=opt/libc-tests/tests/random/inz_split_vpp mode=0555
file path=opt/libc-tests/tests/random/inz_vpp mode=0555
-file path=opt/libc-tests/tests/regex/data/anchor.in mode=0444
-file path=opt/libc-tests/tests/regex/data/backref.in mode=0444
-file path=opt/libc-tests/tests/regex/data/basic.in mode=0444
-file path=opt/libc-tests/tests/regex/data/bracket.in mode=0444
-file path=opt/libc-tests/tests/regex/data/c_comments.in mode=0444
-file path=opt/libc-tests/tests/regex/data/complex.in mode=0444
-file path=opt/libc-tests/tests/regex/data/error.in mode=0444
-file path=opt/libc-tests/tests/regex/data/meta.in mode=0444
-file path=opt/libc-tests/tests/regex/data/nospec.in mode=0444
-file path=opt/libc-tests/tests/regex/data/paren.in mode=0444
-file path=opt/libc-tests/tests/regex/data/regress.in mode=0444
-file path=opt/libc-tests/tests/regex/data/repet_bounded.in mode=0444
-file path=opt/libc-tests/tests/regex/data/repet_multi.in mode=0444
-file path=opt/libc-tests/tests/regex/data/repet_ordinary.in mode=0444
-file path=opt/libc-tests/tests/regex/data/startend.in mode=0444
-file path=opt/libc-tests/tests/regex/data/subexp.in mode=0444
-file path=opt/libc-tests/tests/regex/data/subtle.in mode=0444
-file path=opt/libc-tests/tests/regex/data/word_bound.in mode=0444
-file path=opt/libc-tests/tests/regex/data/zero.in mode=0444
-file path=opt/libc-tests/tests/regex/h_regex mode=0555
-file path=opt/libc-tests/tests/regex/t_regex mode=0555
+file path=opt/libc-tests/tests/regex/data/basic.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/basic.out mode=0444
+file path=opt/libc-tests/tests/regex/data/categorize.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/categorize.out mode=0444
+file path=opt/libc-tests/tests/regex/data/forcedassoc.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/forcedassoc.out mode=0444
+file path=opt/libc-tests/tests/regex/data/leftassoc.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/leftassoc.out mode=0444
+file path=opt/libc-tests/tests/regex/data/nullsubexpr.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/nullsubexpr.out mode=0444
+file path=opt/libc-tests/tests/regex/data/repetition.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/repetition.out mode=0444
+file path=opt/libc-tests/tests/regex/data/rightassoc.dat mode=0444
+file path=opt/libc-tests/tests/regex/data/rightassoc.out mode=0444
+file path=opt/libc-tests/tests/regex/regex_test mode=0555
+file path=opt/libc-tests/tests/regex/testregex mode=0555
file path=opt/libc-tests/tests/select/select.sh mode=0555
file path=opt/libc-tests/tests/select/select_test mode=0555
file path=opt/libc-tests/tests/strcoll-strxfrm-6907.32 mode=0555
diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run
index 17ce2a5b28..a58c46d6c8 100644
--- a/usr/src/test/libc-tests/runfiles/default.run
+++ b/usr/src/test/libc-tests/runfiles/default.run
@@ -57,7 +57,7 @@ outputdir = /var/tmp/test_results
[/opt/libc-tests/tests/random/arc4random_preforksig]
[/opt/libc-tests/tests/random/arc4key.ksh]
-[/opt/libc-tests/tests/regex/t_regex]
+[/opt/libc-tests/tests/regex/regex_test]
[/opt/libc-tests/tests/select/select.sh]
timeout = 600
diff --git a/usr/src/test/libc-tests/tests/regex/Makefile b/usr/src/test/libc-tests/tests/regex/Makefile
index 41227d87b4..6f22161163 100644
--- a/usr/src/test/libc-tests/tests/regex/Makefile
+++ b/usr/src/test/libc-tests/tests/regex/Makefile
@@ -10,7 +10,7 @@
#
#
-# Copyright 2017 Nexenta Systems, Inc.
+# Copyright 2018 Nexenta Systems, Inc.
#
include $(SRC)/Makefile.master
@@ -19,59 +19,40 @@ ROOTOPTPKG= $(ROOT)/opt/libc-tests
TESTDIR= $(ROOTOPTPKG)/tests/regex
DATADIR= $(TESTDIR)/data
-PROG= h_regex
-OBJS= main.o \
- split.o
-
-SHPROG= t_regex
-
-DATA= anchor.in \
- backref.in \
- basic.in \
- bracket.in \
- c_comments.in \
- complex.in \
- error.in \
- meta.in \
- nospec.in \
- paren.in \
- regress.in \
- repet_bounded.in \
- repet_multi.in \
- repet_ordinary.in \
- startend.in \
- subexp.in \
- subtle.in \
- word_bound.in \
- zero.in
+PROG= testregex
+
+SHPROG= regex_test
+
+DATA= basic.dat basic.out \
+ categorize.dat categorize.out \
+ forcedassoc.dat forcedassoc.out \
+ leftassoc.dat leftassoc.out \
+ nullsubexpr.dat nullsubexpr.out \
+ repetition.dat repetition.out \
+ rightassoc.dat rightassoc.out
include $(SRC)/cmd/Makefile.cmd
+CERRWARN += -_gcc=-Wno-parentheses
+CERRWARN += -_gcc=-Wno-uninitialized
+CERRWARN += -_gcc=-Wno-clobbered
+
CMDS= $(PROG:%=$(TESTDIR)/%) $(SHPROG:%=$(TESTDIR)/%)
$(CMDS):= FILEMODE=0555
TESTDATA= $(DATA:%=$(DATADIR)/%)
$(TESTDATA):= FILEMODE=0444
-CPPFLAGS += -I$(SRC)/lib/libc/port/regex
-
.KEEP_STATE:
all: $(PROG)
-$(PROG): $(OBJS)
- $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
- $(POST_PROCESS)
-
$(CMDS): $(TESTDIR)
$(TESTDATA): $(DATADIR)
install: all $(CMDS) $(TESTDATA)
-clean:
- $(RM) $(OBJS)
-
-lint:
+clean lint:
$(TESTDIR) $(DATADIR):
$(INS.dir)
diff --git a/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE b/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE
index 7a7e26d39b..0a002d7c19 100644
--- a/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE
+++ b/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE
@@ -1,23 +1,22 @@
-Copyright (c) 1993 The NetBSD Foundation, Inc.
-All rights reserved.
+Glenn Fowler <glenn.s.fowler@gmail.com>
+AT&T Research
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
+The following license covers testregex.c and all associated test data.
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following disclaimer:
+
+THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE.descrip b/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE.descrip
index e3d50f5ef3..2f50b6f878 100644
--- a/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE.descrip
+++ b/usr/src/test/libc-tests/tests/regex/THIRDPARTYLICENSE.descrip
@@ -1 +1 @@
-LIBC REGEX TESTS
+AT&T Research regex test suite
diff --git a/usr/src/test/libc-tests/tests/regex/data/anchor.in b/usr/src/test/libc-tests/tests/regex/data/anchor.in
deleted file mode 100644
index d145408247..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/anchor.in
+++ /dev/null
@@ -1,33 +0,0 @@
-# anchoring and REG_NEWLINE
-^abc$ & abc abc
-a^b - a^b
-a^b b a^b a^b
-a$b - a$b
-a$b b a$b a$b
-^ & abc @abc
-$ & abc @
-^$ & "" @
-$^ - "" @
-\($\)\(^\) b "" @
-# stop retching, those are legitimate (although disgusting)
-^^ - "" @
-$$ - "" @
-b$ & abNc
-b$ &n abNc b
-^b$ & aNbNc
-^b$ &n aNbNc b
-^$ &n aNNb @Nb
-^$ n abc
-^$ n abcN @
-$^ n aNNb @Nb
-\($\)\(^\) bn aNNb @Nb
-^^ n^ aNNb @Nb
-$$ n aNNb @NN
-^a ^ a
-a$ $ a
-^a ^n aNb
-^b ^n aNb b
-a$ $n bNa
-b$ $n bNa b
-a*(^b$)c* - b b
-a*\(^b$\)c* b b b
diff --git a/usr/src/test/libc-tests/tests/regex/data/backref.in b/usr/src/test/libc-tests/tests/regex/data/backref.in
deleted file mode 100644
index cc59b06e5f..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/backref.in
+++ /dev/null
@@ -1,21 +0,0 @@
-# back references, ugh
-a\(b\)\2c bC ESUBREG
-a\(b\1\)c bC ESUBREG
-a\(b*\)c\1d b abbcbbd abbcbbd bb
-a\(b*\)c\1d b abbcbd
-a\(b*\)c\1d b abbcbbbd
-^\(.\)\1 b abc
-a\([bc]\)\1d b abcdabbd abbd b
-a\(\([bc]\)\2\)*d b abbccd abbccd
-a\(\([bc]\)\2\)*d b abbcbd
-# actually, this next one probably ought to fail, but the spec is unclear
-a\(\(b\)*\2\)*d b abbbd abbbd
-# here is a case that no NFA implementation does right
-\(ab*\)[ab]*\1 b ababaaa ababaaa a
-# check out normal matching in the presence of back refs
-\(a\)\1bcd b aabcd aabcd
-\(a\)\1bc*d b aabcd aabcd
-\(a\)\1bc*d b aabd aabd
-\(a\)\1bc*d b aabcccd aabcccd
-\(a\)\1bc*[ce]d b aabcccd aabcccd
-^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
diff --git a/usr/src/test/libc-tests/tests/regex/data/basic.dat b/usr/src/test/libc-tests/tests/regex/data/basic.dat
new file mode 100644
index 0000000000..5c50f37b4c
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/basic.dat
@@ -0,0 +1,216 @@
+NOTE all standard compliant implementations should pass these : 2002-05-31
+
+BE abracadabra$ abracadabracadabra (7,18)
+BE a...b abababbb (2,7)
+BE XXXXXX ..XXXXXX (2,8)
+E \) () (1,2)
+BE a] a]a (0,2)
+B } } (0,1)
+E \} } (0,1)
+BE \] ] (0,1)
+B ] ] (0,1)
+E ] ] (0,1)
+B { { (0,1)
+B } } (0,1)
+BE ^a ax (0,1)
+BE \^a a^a (1,3)
+BE a\^ a^ (0,2)
+BE a$ aa (1,2)
+BE a\$ a$ (0,2)
+BE ^$ NULL (0,0)
+E $^ NULL (0,0)
+E a($) aa (1,2)(2,2)
+E a*(^a) aa (0,1)(0,1)
+E (..)*(...)* a (0,0)
+E (..)*(...)* abcd (0,4)(2,4)
+E (ab|a)(bc|c) abc (0,3)(0,2)(2,3)
+E (ab)c|abc abc (0,3)(0,2)
+E a{0}b ab (1,2)
+E (a*)(b?)(b+)b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
+E (a*)(b{0,1})(b{1,})b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
+E a{9876543210} NULL BADBR
+E ((a|a)|a) a (0,1)(0,1)(0,1)
+E (a*)(a|aa) aaaa (0,4)(0,3)(3,4)
+E a*(a.|aa) aaaa (0,4)(2,4)
+E a(b)|c(d)|a(e)f aef (0,3)(?,?)(?,?)(1,2)
+E (a|b)?.* b (0,1)(0,1)
+E (a|b)c|a(b|c) ac (0,2)(0,1)
+E (a|b)c|a(b|c) ab (0,2)(?,?)(1,2)
+E (a|b)*c|(a|ab)*c abc (0,3)(1,2)
+E (a|b)*c|(a|ab)*c xc (1,2)
+E (.a|.b).*|.*(.a|.b) xa (0,2)(0,2)
+E a?(ab|ba)ab abab (0,4)(0,2)
+E a?(ac{0}b|ba)ab abab (0,4)(0,2)
+E ab|abab abbabab (0,2)
+E aba|bab|bba baaabbbaba (5,8)
+E aba|bab baaabbbaba (6,9)
+E (aa|aaa)*|(a|aaaaa) aa (0,2)(0,2)
+E (a.|.a.)*|(a|.a...) aa (0,2)(0,2)
+E ab|a xabc (1,3)
+E ab|a xxabc (2,4)
+Ei (Ab|cD)* aBcD (0,4)(2,4)
+BE [^-] --a (2,3)
+BE [a-]* --a (0,3)
+BE [a-m-]* --amoma-- (0,4)
+E :::1:::0:|:::1:1:0: :::0:::1:::1:::0: (8,17)
+E :::1:::0:|:::1:1:1: :::0:::1:::1:::0: (8,17)
+{E [[:upper:]] A (0,1) [[<element>]] not supported
+E [[:lower:]]+ `az{ (1,3)
+E [[:upper:]]+ @AZ[ (1,3)
+BE [[-]] [[-]] (2,4)
+BE [[.NIL.]] NULL ECOLLATE
+BE [[=aleph=]] NULL ECOLLATE
+}
+BE$ \n \n (0,1)
+BEn$ \n \n (0,1)
+BE$ [^a] \n (0,1)
+BE$ \na \na (0,2)
+E (a)(b)(c) abc (0,3)(0,1)(1,2)(2,3)
+BE xxx xxx (0,3)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 6, (0,6)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) 2/7 (0,3)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 1,Feb 6 (5,11)
+E3 ((((((((((((((((((((((((((((((x)))))))))))))))))))))))))))))) x (0,1)(0,1)(0,1)
+E3 ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))* xx (0,2)(1,2)(1,2)
+E a?(ab|ba)* ababababababababababababababababababababababababababababababababababababababababa (0,81)(79,81)
+E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabbbbaa (18,25)
+E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabaa (18,22)
+E aaac|aabc|abac|abbc|baac|babc|bbac|bbbc baaabbbabac (7,11)
+BE$ .* \x01\xff (0,2)
+E aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa (53,57)
+L aaaa\nbbbb\ncccc\nddddd\neeeeee\nfffffff\ngggg\nhhhh\niiiii\njjjjj\nkkkkk\nllll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa NOMATCH
+E a*a*a*a*a*b aaaaaaaaab (0,10)
+BE ^ NULL (0,0)
+BE $ NULL (0,0)
+BE ^$ NULL (0,0)
+BE ^a$ a (0,1)
+BE abc abc (0,3)
+BE abc xabcy (1,4)
+BE abc ababc (2,5)
+BE ab*c abc (0,3)
+BE ab*bc abc (0,3)
+BE ab*bc abbc (0,4)
+BE ab*bc abbbbc (0,6)
+E ab+bc abbc (0,4)
+E ab+bc abbbbc (0,6)
+E ab?bc abbc (0,4)
+E ab?bc abc (0,3)
+E ab?c abc (0,3)
+BE ^abc$ abc (0,3)
+BE ^abc abcc (0,3)
+BE abc$ aabc (1,4)
+BE ^ abc (0,0)
+BE $ abc (3,3)
+BE a.c abc (0,3)
+BE a.c axc (0,3)
+BE a.*c axyzc (0,5)
+BE a[bc]d abd (0,3)
+BE a[b-d]e ace (0,3)
+BE a[b-d] aac (1,3)
+BE a[-b] a- (0,2)
+BE a[b-] a- (0,2)
+BE a] a] (0,2)
+BE a[]]b a]b (0,3)
+BE a[^bc]d aed (0,3)
+BE a[^-b]c adc (0,3)
+BE a[^]b]c adc (0,3)
+E ab|cd abc (0,2)
+E ab|cd abcd (0,2)
+E a\(b a(b (0,3)
+E a\(*b ab (0,2)
+E a\(*b a((b (0,4)
+E ((a)) abc (0,1)(0,1)(0,1)
+E (a)b(c) abc (0,3)(0,1)(2,3)
+E a+b+c aabbabc (4,7)
+E a* aaa (0,3)
+E (a*)* - (0,0)(0,0)
+E (a*)+ - (0,0)(0,0)
+E (a*|b)* - (0,0)(0,0)
+E (a+|b)* ab (0,2)(1,2)
+E (a+|b)+ ab (0,2)(1,2)
+E (a+|b)? ab (0,1)(0,1)
+BE [^ab]* cde (0,3)
+E (^)* - (0,0)(0,0)
+BE a* NULL (0,0)
+E ([abc])*d abbbcd (0,6)(4,5)
+E ([abc])*bcd abcd (0,4)(0,1)
+E a|b|c|d|e e (0,1)
+E (a|b|c|d|e)f ef (0,2)(0,1)
+E ((a*|b))* - (0,0)(0,0)(0,0)
+BE abcd*efg abcdefg (0,7)
+BE ab* xabyabbbz (1,3)
+BE ab* xayabbbz (1,2)
+E (ab|cd)e abcde (2,5)(2,4)
+BE [abhgefdc]ij hij (0,3)
+E (a|b)c*d abcd (1,4)(1,2)
+E (ab|ab*)bc abc (0,3)(0,1)
+E a([bc]*)c* abc (0,3)(1,3)
+E a([bc]*)(c*d) abcd (0,4)(1,3)(3,4)
+E a([bc]+)(c*d) abcd (0,4)(1,3)(3,4)
+E a([bc]*)(c+d) abcd (0,4)(1,2)(2,4)
+E a[bcd]*dcdcde adcdcde (0,7)
+E (ab|a)b*c abc (0,3)(0,2)
+E ((a)(b)c)(d) abcd (0,4)(0,3)(0,1)(1,2)(3,4)
+BE [A-Za-z_][A-Za-z0-9_]* alpha (0,5)
+E ^a(bc+|b[eh])g|.h$ abh (1,3)
+E (bc+d$|ef*g.|h?i(j|k)) effgz (0,5)(0,5)
+E (bc+d$|ef*g.|h?i(j|k)) ij (0,2)(0,2)(1,2)
+E (bc+d$|ef*g.|h?i(j|k)) reffgz (1,6)(1,6)
+E (((((((((a))))))))) a (0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)
+BE multiple words multiple words yeah (0,14)
+E (.*)c(.*) abcde (0,5)(0,2)(3,5)
+BE abcd abcd (0,4)
+E a(bc)d abcd (0,4)(1,3)
+E a[-]?c ac (0,3)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qaddafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mo'ammar Gadhafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Kaddafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qadhafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gadafi (0,14)(?,?)(10,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadafi (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moamar Gaddafi (0,14)(?,?)(9,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadhdhafi (0,18)(?,?)(13,15)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Khaddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafy (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghadafi (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muamar Kaddafi (0,14)(?,?)(9,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Quathafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gheddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Khadafy (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Qudhafi (0,15)(?,?)(10,12)
+E a+(b|c)*d+ aabcdd (0,6)(3,4)
+E ^.+$ vivi (0,4)
+E ^(.+)$ vivi (0,4)(0,4)
+E ^([^!.]+).att.com!(.+)$ gryphon.att.com!eby (0,19)(0,7)(16,19)
+E ^([^!]+!)?([^!]+)$ bas (0,3)(?,?)(0,3)
+E ^([^!]+!)?([^!]+)$ bar!bas (0,7)(0,4)(4,7)
+E ^([^!]+!)?([^!]+)$ foo!bas (0,7)(0,4)(4,7)
+E ^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(4,8)(8,11)
+E ((foo)|(bar))!bas bar!bas (0,7)(0,3)(?,?)(0,3)
+E ((foo)|(bar))!bas foo!bar!bas (4,11)(4,7)(?,?)(4,7)
+E ((foo)|(bar))!bas foo!bas (0,7)(0,3)(0,3)
+E ((foo)|bar)!bas bar!bas (0,7)(0,3)
+E ((foo)|bar)!bas foo!bar!bas (4,11)(4,7)
+E ((foo)|bar)!bas foo!bas (0,7)(0,3)(0,3)
+E (foo|(bar))!bas bar!bas (0,7)(0,3)(0,3)
+E (foo|(bar))!bas foo!bar!bas (4,11)(4,7)(4,7)
+E (foo|(bar))!bas foo!bas (0,7)(0,3)
+E (foo|bar)!bas bar!bas (0,7)(0,3)
+E (foo|bar)!bas foo!bar!bas (4,11)(4,7)
+E (foo|bar)!bas foo!bas (0,7)(0,3)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bas (0,3)(?,?)(0,3)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bar!bas (0,7)(0,4)(4,7)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(?,?)(?,?)(4,8)(8,11)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bas (0,7)(0,4)(4,7)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bas (0,3)(0,3)(?,?)(0,3)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bar!bas (0,7)(0,7)(0,4)(4,7)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bas (0,7)(0,7)(0,4)(4,7)
+E .*(/XXX).* /XXX (0,4)(0,4)
+E .*(\\XXX).* \XXX (0,4)(0,4)
+E \\XXX \XXX (0,4)
+E .*(/000).* /000 (0,4)(0,4)
+E .*(\\000).* \000 (0,4)(0,4)
+E \\000 \000 (0,4)
diff --git a/usr/src/test/libc-tests/tests/regex/data/basic.in b/usr/src/test/libc-tests/tests/regex/data/basic.in
deleted file mode 100644
index d1e3aa9dad..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/basic.in
+++ /dev/null
@@ -1,5 +0,0 @@
-# basics
-a & a a
-abc & abc abc
-abc|de - abc abc
-a|b|c - abc a
diff --git a/usr/src/test/libc-tests/tests/regex/data/basic.out b/usr/src/test/libc-tests/tests/regex/data/basic.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/basic.out
diff --git a/usr/src/test/libc-tests/tests/regex/data/bracket.in b/usr/src/test/libc-tests/tests/regex/data/bracket.in
deleted file mode 100644
index 53a0b20d3c..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/bracket.in
+++ /dev/null
@@ -1,55 +0,0 @@
-# brackets, and numerous perversions thereof
-a[b]c & abc abc
-a[ab]c & abc abc
-a[^ab]c & adc adc
-a[]b]c & a]c a]c
-a[[b]c & a[c a[c
-a[-b]c & a-c a-c
-a[^]b]c & adc adc
-a[^-b]c & adc adc
-a[b-]c & a-c a-c
-a[b &C EBRACK
-a[] &C EBRACK
-a[1-3]c & a2c a2c
-a[3-1]c &C ERANGE
-a[1-3-5]c &C ERANGE
-a[[.-.]--]c & a-c a-c
-a[1- &C ERANGE
-a[[. &C EBRACK
-a[[.x &C EBRACK
-a[[.x. &C EBRACK
-a[[.x.] &C EBRACK
-a[[.x.]] & ax ax
-a[[.x,.]] &C ECOLLATE
-a[[.one.]]b & a1b a1b
-a[[.notdef.]]b &C ECOLLATE
-a[[.].]]b & a]b a]b
-a[[:alpha:]]c & abc abc
-a[[:notdef:]]c &C ECTYPE
-a[[: &C EBRACK
-a[[:alpha &C EBRACK
-a[[:alpha:] &C EBRACK
-a[[:alpha,:] &C ECTYPE
-a[[:]:]]b &C ECTYPE
-a[[:-:]]b &C ECTYPE
-a[[:alph:]] &C ECTYPE
-a[[:alphabet:]] &C ECTYPE
-[[:alnum:]]+ - -%@a0X- a0X
-[[:alpha:]]+ - -%@aX0- aX
-[[:blank:]]+ - aSSTb SST
-[[:cntrl:]]+ - aNTb NT
-[[:digit:]]+ - a019b 019
-[[:graph:]]+ - Sa%bS a%b
-[[:lower:]]+ - AabC ab
-[[:print:]]+ - NaSbN aSb
-[[:punct:]]+ - S%-&T %-&
-[[:space:]]+ - aSNTb SNT
-[[:upper:]]+ - aBCd BC
-[[:xdigit:]]+ - p0f3Cq 0f3C
-a[[=b=]]c & abc abc
-a[[= &C EBRACK
-a[[=b &C EBRACK
-a[[=b= &C EBRACK
-a[[=b=] &C EBRACK
-a[[=b,=]] &C ECOLLATE
-a[[=one=]]b & a1b a1b
diff --git a/usr/src/test/libc-tests/tests/regex/data/c_comments.in b/usr/src/test/libc-tests/tests/regex/data/c_comments.in
deleted file mode 100644
index ea3faf9ddf..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/c_comments.in
+++ /dev/null
@@ -1,17 +0,0 @@
-# Let's have some fun -- try to match a C comment.
-# first the obvious, which looks okay at first glance...
-/\*.*\*/ - /*x*/ /*x*/
-# but...
-/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/
-# okay, we must not match */ inside; try to do that...
-/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/
-/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/
-# but...
-/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/
-# and a still fancier version, which does it right (I think)...
-/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/
-/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/
-/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/
-/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/
-/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/
-/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/
diff --git a/usr/src/test/libc-tests/tests/regex/data/categorize.dat b/usr/src/test/libc-tests/tests/regex/data/categorize.dat
new file mode 100644
index 0000000000..d34851278f
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/categorize.dat
@@ -0,0 +1,62 @@
+NOTE regex implementation categorization 2004-05-31
+
+?E aa* xaxaax (1,2) POSITION=leftmost
+; POSITION=bug
+
+?E (a*)(ab)*(b*) abc (0,2)(0,1)(?,?)(1,2) ASSOCIATIVITY=right
+|E (a*)(ab)*(b*) abc (0,2)(0,0)(0,2)(2,2) ASSOCIATIVITY=left
+; ASSOCIATIVITY=bug
+
+?E ((a*)(ab)*)((b*)(a*)) aba (0,3)(0,2)(0,0)(0,2)(2,3)(2,2)(2,3) SUBEXPRESSION=precedence
+|E ((a*)(ab)*)((b*)(a*)) aba (0,3)(0,1)(0,1)(?,?)(1,3)(1,2)(2,3) SUBEXPRESSION=grouping
+; SUBEXPRESSION=bug
+
+?E (...?.?)* xxxxxx (0,6)(4,6) REPEAT_LONGEST=first
+|E (...?.?)* xxxxxx (0,6)(2,6) REPEAT_LONGEST=last
+|E (...?.?)* xxxxxx OK REPEAT_LONGEST=unknown
+; REPEAT_LONGEST=bug
+
+?E (a|ab)(bc|c) abcabc (0,3)(0,2)(2,3) EXPECTED
+|E (a|ab)(bc|c) abcabc (0,3)(0,1)(1,3) BUG=alternation-order
+; BUG=alternation-order-UNKNOWN
+
+?E (aba|a*b)(aba|a*b) ababa (0,5)(0,2)(2,5) EXPECTED
+|E (aba|a*b)(aba|a*b) ababa (0,4)(0,3)(3,4) BUG=first-match
+; BUG=unknown-match
+
+?B a\(b\)*\1 a NOMATCH EXPECTED
+|B a\(b\)*\1 a (0,1) BUG=nomatch-match
+|B a\(b\)*\1 abab (0,2)(1,2) # BUG=repeat-any
+; BUG=nomatch-match-UNKNOWN
+
+?E (a*){2} xxxxx (0,0)(0,0) EXPECTED
+|E (a*){2} xxxxx (5,5)(5,5) BUG=range-null
+; BUG=range-null-UNKNOWN
+
+?B a\(b\)*\1 abab NOMATCH EXPECTED
+|B a\(b\)*\1 abab (0,1) # BUG=nomatch-match
+|B a\(b\)*\1 abab (0,2)(1,2) BUG=repeat-any
+; BUG=repeat-any-UNKNOWN
+
+?E (a*)* a (0,1)(0,1) EXPECTED
+|E (a*)* ax (0,1)(0,1) BUG=repeat-null-unknown
+|E (a*)* a (0,1)(1,1) BUG=repeat-null
+; BUG=repeat-null-UNKNOWN
+
+?E (aba|a*b)* ababa (0,5)(2,5) EXPECTED
+|E (aba|a*b)* ababa (0,5)(3,4) BUG=repeat-short
+|E (aba|a*b)* ababa (0,4)(3,4) # LENGTH=first
+; BUG=repeat-short-UNKNOWN
+
+?E (a(b)?)+ aba (0,3)(2,3) EXPECTED
+|E (a(b)?)+ aba (0,3)(2,3)(1,2) BUG=repeat-artifact
+; BUG=repeat-artifact-UNKNOWN
+
+?B \(a\(b\)*\)*\2 abab NOMATCH EXPECTED
+|B \(a\(b\)*\)*\2 abab (0,4)(2,3)(1,2) BUG=repeat-artifact-nomatch
+; BUG=repeat-artifact-nomatch-UNKNOWN
+
+?E (a?)((ab)?)(b?)a?(ab)?b? abab (0,4)(0,1)(1,1)(?,?)(1,2)(2,4) BUG=subexpression-first
+|E .*(.*) ab (0,2)(2,2) EXPECTED
+|E .*(.*) ab (0,2)(0,2) BUG=subexpression-first
+; BUG=subexpression-first-UNKNOWN
diff --git a/usr/src/test/libc-tests/tests/regex/data/categorize.out b/usr/src/test/libc-tests/tests/regex/data/categorize.out
new file mode 100644
index 0000000000..68e9b43201
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/categorize.out
@@ -0,0 +1,13 @@
+NOTE ASSOCIATIVITY=bug
+NOTE SUBEXPRESSION=bug
+NOTE REPEAT_LONGEST=bug
+NOTE BUG=alternation-order-UNKNOWN
+NOTE BUG=unknown-match
+NOTE BUG=nomatch-match-UNKNOWN
+NOTE BUG=range-null-UNKNOWN
+NOTE BUG=repeat-any-UNKNOWN
+NOTE BUG=repeat-null-UNKNOWN
+NOTE BUG=repeat-short-UNKNOWN
+NOTE BUG=repeat-artifact-UNKNOWN
+NOTE BUG=repeat-artifact-nomatch-UNKNOWN
+NOTE BUG=subexpression-first-UNKNOWN
diff --git a/usr/src/test/libc-tests/tests/regex/data/complex.in b/usr/src/test/libc-tests/tests/regex/data/complex.in
deleted file mode 100644
index e1140588e7..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/complex.in
+++ /dev/null
@@ -1,23 +0,0 @@
-# complexities
-a(((b)))c - abc abc
-a(b|(c))d - abd abd
-a(b*|c)d - abbd abbd
-# just gotta have one DFA-buster, of course
-a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
-# and an inline expansion in case somebody gets tricky
-a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
-# and in case somebody just slips in an NFA...
-a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
-# fish for anomalies as the number of states passes 32
-12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
-123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
-1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
-12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
-123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
-# and one really big one, beyond any plausible word width
-1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
-# fish for problems as brackets go past 8
-[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
-[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
-[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
-[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
diff --git a/usr/src/test/libc-tests/tests/regex/data/error.in b/usr/src/test/libc-tests/tests/regex/data/error.in
deleted file mode 100644
index ea106f1653..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/error.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# certain syntax errors and non-errors
-| C BADPAT
-| b | |
-* C BADRPT
-* b * *
-+ C BADRPT
-? C BADRPT
-"" &C BADPAT
-() - abc @abc
-\(\) b abc @abc
-a||b C BADPAT
-|ab C BADPAT
-ab| C BADPAT
-(|a)b C BADPAT
-(a|)b C BADPAT
-(*a) C BADRPT
-(+a) C BADRPT
-(?a) C BADRPT
-({1}a) C BADRPT
-\(\{1\}a\) bC BADRPT
-(a|*b) C BADRPT
-(a|+b) C BADRPT
-(a|?b) C BADRPT
-(a|{1}b) C BADRPT
-^* C BADRPT
-^* b * *
-^+ C BADRPT
-^? C BADRPT
-^{1} C BADRPT
-^\{1\} bC BADRPT
diff --git a/usr/src/test/libc-tests/tests/regex/data/forcedassoc.dat b/usr/src/test/libc-tests/tests/regex/data/forcedassoc.dat
new file mode 100644
index 0000000000..39f3111dab
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/forcedassoc.dat
@@ -0,0 +1,30 @@
+NOTE left-assoc:pass-all right-assoc:pass-all : 2002-04-29
+
+E (a|ab)(c|bcd) abcd (0,4)(0,1)(1,4)
+E (a|ab)(bcd|c) abcd (0,4)(0,1)(1,4)
+E (ab|a)(c|bcd) abcd (0,4)(0,1)(1,4)
+E (ab|a)(bcd|c) abcd (0,4)(0,1)(1,4)
+E ((a|ab)(c|bcd))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((a|ab)(bcd|c))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((ab|a)(c|bcd))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((ab|a)(bcd|c))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E (a|ab)((c|bcd)(d*)) abcd (0,4)(0,2)(2,4)(2,3)(3,4)
+E (a|ab)((bcd|c)(d*)) abcd (0,4)(0,2)(2,4)(2,3)(3,4)
+E (ab|a)((c|bcd)(d*)) abcd (0,4)(0,2)(2,4)(2,3)(3,4)
+E (ab|a)((bcd|c)(d*)) abcd (0,4)(0,2)(2,4)(2,3)(3,4)
+E (a*)(b|abc) abc (0,3)(0,0)(0,3)
+E (a*)(abc|b) abc (0,3)(0,0)(0,3)
+E ((a*)(b|abc))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E ((a*)(abc|b))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E (a*)((b|abc)(c*)) abc (0,3)(0,1)(1,3)(1,2)(2,3)
+E (a*)((abc|b)(c*)) abc (0,3)(0,1)(1,3)(1,2)(2,3)
+E (a*)(b|abc) abc (0,3)(0,0)(0,3)
+E (a*)(abc|b) abc (0,3)(0,0)(0,3)
+E ((a*)(b|abc))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E ((a*)(abc|b))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E (a*)((b|abc)(c*)) abc (0,3)(0,1)(1,3)(1,2)(2,3)
+E (a*)((abc|b)(c*)) abc (0,3)(0,1)(1,3)(1,2)(2,3)
+E (a|ab) ab (0,2)(0,2)
+E (ab|a) ab (0,2)(0,2)
+E (a|ab)(b*) ab (0,2)(0,2)(2,2)
+E (ab|a)(b*) ab (0,2)(0,2)(2,2)
diff --git a/usr/src/test/libc-tests/tests/regex/data/forcedassoc.out b/usr/src/test/libc-tests/tests/regex/data/forcedassoc.out
new file mode 100644
index 0000000000..682faa25af
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/forcedassoc.out
@@ -0,0 +1,8 @@
+E ((a|ab)(c|bcd))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((a|ab)(bcd|c))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((ab|a)(c|bcd))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((ab|a)(bcd|c))(d*) abcd (0,4)(0,4)(0,1)(1,4)(4,4)
+E ((a*)(b|abc))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E ((a*)(abc|b))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E ((a*)(b|abc))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
+E ((a*)(abc|b))(c*) abc (0,3)(0,3)(0,0)(0,3)(3,3)
diff --git a/usr/src/test/libc-tests/tests/regex/data/leftassoc.dat b/usr/src/test/libc-tests/tests/regex/data/leftassoc.dat
new file mode 100644
index 0000000000..9c068c61bf
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/leftassoc.dat
@@ -0,0 +1,16 @@
+NOTE left-assoc:pass-all right-assoc:pass-none : 2002-04-29
+
+E (a|ab)(c|bcd)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (a|ab)(bcd|c)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(c|bcd)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(bcd|c)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+
+E (a*)(b|abc)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(b|abc)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,0)(0,3)(3,3)
+
+E (a|ab)(c|bcd)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (a|ab)(bcd|c)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(c|bcd)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(bcd|c)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
diff --git a/usr/src/test/libc-tests/tests/regex/data/leftassoc.out b/usr/src/test/libc-tests/tests/regex/data/leftassoc.out
new file mode 100644
index 0000000000..c147020747
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/leftassoc.out
@@ -0,0 +1,12 @@
+E (a|ab)(c|bcd)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (a|ab)(bcd|c)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(c|bcd)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(bcd|c)(d*) abcd (0,4)(0,1)(1,4)(4,4)
+E (a*)(b|abc)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(b|abc)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,0)(0,3)(3,3)
+E (a|ab)(c|bcd)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (a|ab)(bcd|c)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(c|bcd)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
+E (ab|a)(bcd|c)(d|.*) abcd (0,4)(0,1)(1,4)(4,4)
diff --git a/usr/src/test/libc-tests/tests/regex/data/meta.in b/usr/src/test/libc-tests/tests/regex/data/meta.in
deleted file mode 100644
index 4533d3591b..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/meta.in
+++ /dev/null
@@ -1,21 +0,0 @@
-# metacharacters, backslashes
-a.c & abc abc
-a[bc]d & abd abd
-a\*c & a*c a*c
-a\\b & a\b a\b
-a\\\*b & a\*b a\*b
-a\bc & abc abc
-a\ &C EESCAPE
-a\\bc & a\bc a\bc
-\{ bC BADRPT
-a\[b & a[b a[b
-a[b &C EBRACK
-# trailing $ is a peculiar special case for the BRE code
-a$ & a a
-a$ & a$
-a\$ & a
-a\$ & a$ a$
-a\\$ & a
-a\\$ & a$
-a\\$ & a\$
-a\\$ & a\ a\
diff --git a/usr/src/test/libc-tests/tests/regex/data/nospec.in b/usr/src/test/libc-tests/tests/regex/data/nospec.in
deleted file mode 100644
index d95f81d1d7..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/nospec.in
+++ /dev/null
@@ -1,7 +0,0 @@
-# plain strings, with the NOSPEC flag
-abc m abc abc
-abc m xabcy abc
-abc m xyz
-a*b m aba*b a*b
-a*b m ab
-"" mC BADPAT
diff --git a/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.dat b/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.dat
new file mode 100644
index 0000000000..c73d8f09ee
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.dat
@@ -0,0 +1,73 @@
+NOTE null subexpression matches : 2002-06-06
+
+E (a*)* a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a*)+ a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a+)* a (0,1)(0,1)
+E SAME x (0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a+)+ a (0,1)(0,1)
+E SAME x NOMATCH
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+
+E ([a]*)* a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E ([a]*)+ a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E ([^b]*)* a (0,1)(0,1)
+E SAME b (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaab (0,6)(0,6)
+E ([ab]*)* a (0,1)(0,1)
+E SAME aaaaaa (0,6)(0,6)
+E SAME ababab (0,6)(0,6)
+E SAME bababa (0,6)(0,6)
+E SAME b (0,1)(0,1)
+E SAME bbbbbb (0,6)(0,6)
+E SAME aaaabcde (0,5)(0,5)
+E ([^a]*)* b (0,1)(0,1)
+E SAME bbbbbb (0,6)(0,6)
+E SAME aaaaaa (0,0)(0,0)
+E ([^ab]*)* ccccxx (0,6)(0,6)
+E SAME ababab (0,0)(0,0)
+
+E ((z)+|a)* zabcde (0,2)(1,2)
+
+{E a+? aaaaaa (0,1) no *? +? mimimal match ops
+E (a) aaa (0,1)(0,1)
+E (a*?) aaa (0,0)(0,0)
+E (a)*? aaa (0,0)
+E (a*?)*? aaa (0,0)
+}
+
+B \(a*\)*\(x\) x (0,1)(0,0)(0,1)
+B \(a*\)*\(x\) ax (0,2)(0,1)(1,2)
+B \(a*\)*\(x\) axa (0,2)(0,1)(1,2)
+B \(a*\)*\(x\)\(\1\) x (0,1)(0,0)(0,1)(1,1)
+B \(a*\)*\(x\)\(\1\) ax (0,2)(1,1)(1,2)(2,2)
+B \(a*\)*\(x\)\(\1\) axa (0,3)(0,1)(1,2)(2,3)
+B \(a*\)*\(x\)\(\1\)\(x\) axax (0,4)(0,1)(1,2)(2,3)(3,4)
+B \(a*\)*\(x\)\(\1\)\(x\) axxa (0,3)(1,1)(1,2)(2,2)(2,3)
+
+E (a*)*(x) x (0,1)(0,0)(0,1)
+E (a*)*(x) ax (0,2)(0,1)(1,2)
+E (a*)*(x) axa (0,2)(0,1)(1,2)
+
+E (a*)+(x) x (0,1)(0,0)(0,1)
+E (a*)+(x) ax (0,2)(0,1)(1,2)
+E (a*)+(x) axa (0,2)(0,1)(1,2)
+
+E (a*){2}(x) x (0,1)(0,0)(0,1)
+E (a*){2}(x) ax (0,2)(1,1)(1,2)
+E (a*){2}(x) axa (0,2)(1,1)(1,2)
diff --git a/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.out b/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.out
new file mode 100644
index 0000000000..bede877a81
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/nullsubexpr.out
@@ -0,0 +1,32 @@
+E (a*)* a (0,1)(0,1)
+E (a*)* aaaaaa (0,6)(0,6)
+E (a*)* aaaaaax (0,6)(0,6)
+E (a*)+ a (0,1)(0,1)
+E (a*)+ aaaaaa (0,6)(0,6)
+E (a*)+ aaaaaax (0,6)(0,6)
+E ([a]*)* a (0,1)(0,1)
+E ([a]*)* aaaaaa (0,6)(0,6)
+E ([a]*)* aaaaaax (0,6)(0,6)
+E ([a]*)+ a (0,1)(0,1)
+E ([a]*)+ aaaaaa (0,6)(0,6)
+E ([a]*)+ aaaaaax (0,6)(0,6)
+E ([^b]*)* a (0,1)(0,1)
+E ([^b]*)* aaaaaa (0,6)(0,6)
+E ([^b]*)* aaaaaab (0,6)(0,6)
+E ([ab]*)* a (0,1)(0,1)
+E ([ab]*)* aaaaaa (0,6)(0,6)
+E ([ab]*)* ababab (0,6)(0,6)
+E ([ab]*)* bababa (0,6)(0,6)
+E ([ab]*)* b (0,1)(0,1)
+E ([ab]*)* bbbbbb (0,6)(0,6)
+E ([ab]*)* aaaabcde (0,5)(0,5)
+E ([^a]*)* b (0,1)(0,1)
+E ([^a]*)* bbbbbb (0,6)(0,6)
+E ([^ab]*)* ccccxx (0,6)(0,6)
+}
+B \(a*\)*\(x\) ax (0,2)(0,1)(1,2)
+B \(a*\)*\(x\) axa (0,2)(0,1)(1,2)
+E (a*)*(x) ax (0,2)(0,1)(1,2)
+E (a*)*(x) axa (0,2)(0,1)(1,2)
+E (a*)+(x) ax (0,2)(0,1)(1,2)
+E (a*)+(x) axa (0,2)(0,1)(1,2)
diff --git a/usr/src/test/libc-tests/tests/regex/data/paren.in b/usr/src/test/libc-tests/tests/regex/data/paren.in
deleted file mode 100644
index c3e8a295fe..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/paren.in
+++ /dev/null
@@ -1,19 +0,0 @@
-# parentheses and perversions thereof
-a(b)c - abc abc
-a\(b\)c b abc abc
-a( C EPAREN
-a( b a( a(
-a\( - a( a(
-a\( bC EPAREN
-a\(b bC EPAREN
-a(b C EPAREN
-a(b b a(b a(b
-# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
-a) b EPAREN
-) b EPAREN
-# end gagging (in a just world, those *should* give EPAREN)
-a) b a) a)
-a\) bC EPAREN
-\) bC EPAREN
-a()b - ab ab
-a\(\)b b ab ab
diff --git a/usr/src/test/libc-tests/tests/regex/data/regress.in b/usr/src/test/libc-tests/tests/regex/data/regress.in
deleted file mode 100644
index afd832a51c..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/regress.in
+++ /dev/null
@@ -1,9 +0,0 @@
-# past problems, and suspected problems
-(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
-abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
-abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
-(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
-CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
-Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz
-a?b - ab ab
--\{0,1\}[0-9]*$ b -5 -5
diff --git a/usr/src/test/libc-tests/tests/regex/data/repet_bounded.in b/usr/src/test/libc-tests/tests/regex/data/repet_bounded.in
deleted file mode 100644
index 74a621dd1d..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/repet_bounded.in
+++ /dev/null
@@ -1,58 +0,0 @@
-# the dreaded bounded repetitions
-{ C BADRPT
-{ b { {
-\{ - { {
-\{ bC BADRPT
-{} C BADRPT
-{} b {} {}
-\{\} - {} {}
-\{\} bC BADRPT
-} & } }
-\} & } }
-{abc b {abc {abc
-{abc C BADRPT
-{1 C BADRPT
-{1} C BADRPT
-a{b b a{b a{b
-a{b C BADRPT
-a{1}b - ab ab
-a\{1\}b b ab ab
-a{1,}b - ab ab
-a\{1,\}b b ab ab
-a{1,2}b - aab aab
-a\{1,2\}b b aab aab
-a{1 C EBRACE
-a\{1 bC EBRACE
-a{1a C EBRACE
-a\{1a bC EBRACE
-a{1a} C BADBR
-a\{1a\} bC BADBR
-a{,2} b a{,2} a{,2}
-a{,2} C BADBR
-a\{,2\} bC BADBR
-a{,} b a{,} a{,}
-a{,} C BADBR
-a\{,\} bC BADBR
-a{1,x} C BADBR
-a\{1,x\} bC BADBR
-a{1,x C EBRACE
-a\{1,x bC EBRACE
-a{300} C BADBR
-a\{300\} bC BADBR
-a{1,0} C BADBR
-a\{1,0\} bC BADBR
-ab{0,0}c - abcac ac
-ab\{0,0\}c b abcac ac
-ab{0,1}c - abcac abc
-ab\{0,1\}c b abcac abc
-ab{0,3}c - abbcac abbc
-ab\{0,3\}c b abbcac abbc
-ab{1,1}c - acabc abc
-ab\{1,1\}c b acabc abc
-ab{1,3}c - acabc abc
-ab\{1,3\}c b acabc abc
-ab{2,2}c - abcabbc abbc
-ab\{2,2\}c b abcabbc abbc
-ab{2,4}c - abcabbc abbc
-ab\{2,4\}c b abcabbc abbc
-((a{1,10}){1,10}){1,10} - a a a,a
diff --git a/usr/src/test/libc-tests/tests/regex/data/repet_multi.in b/usr/src/test/libc-tests/tests/regex/data/repet_multi.in
deleted file mode 100644
index 2e9c68a50f..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/repet_multi.in
+++ /dev/null
@@ -1,22 +0,0 @@
-# multiple repetitions
-a** &C BADRPT
-a++ C BADRPT
-a?? C BADRPT
-a*+ C BADRPT
-a*? C BADRPT
-a+* C BADRPT
-a+? C BADRPT
-a?* C BADRPT
-a?+ C BADRPT
-a{1}{1} C BADRPT
-a*{1} C BADRPT
-a+{1} C BADRPT
-a?{1} C BADRPT
-a{1}* C BADRPT
-a{1}+ C BADRPT
-a{1}? C BADRPT
-a*{b} b a{b} a{b}
-a*{b} C BADRPT
-a\{1\}\{1\} bC BADRPT
-a*\{1\} bC BADRPT
-a\{1\}* bC BADRPT
diff --git a/usr/src/test/libc-tests/tests/regex/data/repet_ordinary.in b/usr/src/test/libc-tests/tests/regex/data/repet_ordinary.in
deleted file mode 100644
index 08bc286e5b..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/repet_ordinary.in
+++ /dev/null
@@ -1,10 +0,0 @@
-# ordinary repetitions
-ab*c & abc abc
-ab+c - abc abc
-ab?c - abc abc
-a\(*\)b b a*b a*b
-a\(**\)b b ab ab
-a\(***\)b bC BADRPT
-*a b *a *a
-**a b a a
-***a bC BADRPT
diff --git a/usr/src/test/libc-tests/tests/regex/data/repetition.dat b/usr/src/test/libc-tests/tests/regex/data/repetition.dat
new file mode 100644
index 0000000000..92944b5833
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/repetition.dat
@@ -0,0 +1,140 @@
+NOTE implicit vs. explicit repetitions : 2009-02-02
+
+# Glenn Fowler <glenn.s.fowler@gmail.com>
+# conforming matches (column 4) must match one of the following BREs
+# NOMATCH
+# (0,.)\((\(.\),\(.\))(?,?)(\2,\3)\)*
+# (0,.)\((\(.\),\(.\))(\2,\3)(?,?)\)*
+# i.e., each 3-tuple has two identical elements and one (?,?)
+
+E ((..)|(.)) NULL NOMATCH
+E ((..)|(.))((..)|(.)) NULL NOMATCH
+E ((..)|(.))((..)|(.))((..)|(.)) NULL NOMATCH
+
+E ((..)|(.)){1} NULL NOMATCH
+E ((..)|(.)){2} NULL NOMATCH
+E ((..)|(.)){3} NULL NOMATCH
+
+E ((..)|(.))* NULL (0,0)
+
+E ((..)|(.)) a (0,1)(0,1)(?,?)(0,1)
+E ((..)|(.))((..)|(.)) a NOMATCH
+E ((..)|(.))((..)|(.))((..)|(.)) a NOMATCH
+
+E ((..)|(.)){1} a (0,1)(0,1)(?,?)(0,1)
+E ((..)|(.)){2} a NOMATCH
+E ((..)|(.)){3} a NOMATCH
+
+E ((..)|(.))* a (0,1)(0,1)(?,?)(0,1)
+
+E ((..)|(.)) aa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aa (0,2)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)
+E ((..)|(.))((..)|(.))((..)|(.)) aa NOMATCH
+
+E ((..)|(.)){1} aa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aa (0,2)(1,2)(?,?)(1,2)
+E ((..)|(.)){3} aa NOMATCH
+
+E ((..)|(.))* aa (0,2)(0,2)(0,2)(?,?)
+
+E ((..)|(.)) aaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaa (0,3)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)
+E ((..)|(.))((..)|(.))((..)|(.)) aaa (0,3)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)(2,3)(?,?)(2,3)
+
+E ((..)|(.)){1} aaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaa (0,3)(2,3)(?,?)(2,3)
+E ((..)|(.)){3} aaa (0,3)(2,3)(?,?)(2,3)
+
+E ((..)|(.))* aaa (0,3)(2,3)(?,?)(2,3)
+
+E ((..)|(.)) aaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)(3,4)(?,?)(3,4)
+
+E ((..)|(.)){1} aaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaa (0,4)(2,4)(2,4)(?,?)
+E ((..)|(.)){3} aaaa (0,4)(3,4)(?,?)(3,4)
+
+E ((..)|(.))* aaaa (0,4)(2,4)(2,4)(?,?)
+
+E ((..)|(.)) aaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaaa (0,5)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,5)(?,?)(4,5)
+
+E ((..)|(.)){1} aaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaaa (0,4)(2,4)(2,4)(?,?)
+E ((..)|(.)){3} aaaaa (0,5)(4,5)(?,?)(4,5)
+
+E ((..)|(.))* aaaaa (0,5)(4,5)(?,?)(4,5)
+
+E ((..)|(.)) aaaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaaaa (0,6)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,6)(4,6)(?,?)
+
+E ((..)|(.)){1} aaaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaaaa (0,4)(2,4)(2,4)(?,?)
+E ((..)|(.)){3} aaaaaa (0,6)(4,6)(4,6)(?,?)
+
+E ((..)|(.))* aaaaaa (0,6)(4,6)(4,6)(?,?)
+
+NOTE additional repetition tests graciously provided by Chris Kuklewicz www.haskell.org 2009-02-02
+
+# These test a bug in OS X / FreeBSD / NetBSD, and libtree.
+# Linux/GLIBC gets the {8,} and {8,8} wrong.
+
+:HA#100:E X(.?){0,}Y X1234567Y (0,9)(7,8)
+:HA#101:E X(.?){1,}Y X1234567Y (0,9)(7,8)
+:HA#102:E X(.?){2,}Y X1234567Y (0,9)(7,8)
+:HA#103:E X(.?){3,}Y X1234567Y (0,9)(7,8)
+:HA#104:E X(.?){4,}Y X1234567Y (0,9)(7,8)
+:HA#105:E X(.?){5,}Y X1234567Y (0,9)(7,8)
+:HA#106:E X(.?){6,}Y X1234567Y (0,9)(7,8)
+:HA#107:E X(.?){7,}Y X1234567Y (0,9)(7,8)
+:HA#108:E X(.?){8,}Y X1234567Y (0,9)(8,8)
+:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(7,8)
+:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(7,8)
+:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(7,8)
+:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(7,8)
+:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(7,8)
+:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(7,8)
+:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(7,8)
+:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(7,8)
+:HA#118:E X(.?){8,8}Y X1234567Y (0,9)(8,8)
+
+# These test a fixed bug in my regex-tdfa that did not keep the expanded
+# form properly grouped, so right association did the wrong thing with
+# these ambiguous patterns (crafted just to test my code when I became
+# suspicious of my implementation). The first subexpression should use
+# "ab" then "a" then "bcd".
+
+# OS X / FreeBSD / NetBSD badly fail many of these, with impossible
+# results like (0,6)(4,5)(6,6).
+
+:HA#260:E (a|ab|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#261:E (a|ab|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#262:E (a|ab|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#263:E (a|ab|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#264:E (a|ab|c|bcd){4,}(d*) ababcd NOMATCH
+:HA#265:E (a|ab|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#266:E (a|ab|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#267:E (a|ab|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#268:E (a|ab|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#269:E (a|ab|c|bcd){4,10}(d*) ababcd NOMATCH
+:HA#270:E (a|ab|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#271:E (a|ab|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
+
+# The above worked on Linux/GLIBC but the following often fail.
+# They also trip up OS X / FreeBSD / NetBSD:
+
+:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#284:E (ab|a|c|bcd){4,}(d*) ababcd NOMATCH
+:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#289:E (ab|a|c|bcd){4,10}(d*) ababcd NOMATCH
+:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
diff --git a/usr/src/test/libc-tests/tests/regex/data/repetition.out b/usr/src/test/libc-tests/tests/regex/data/repetition.out
new file mode 100644
index 0000000000..4387a66752
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/repetition.out
@@ -0,0 +1,37 @@
+E ((..)|(.)){2} aaa (0,3)(2,3)(?,?)(2,3)
+E ((..)|(.)){3} aaaa (0,4)(3,4)(?,?)(3,4)
+E ((..)|(.)){3} aaaaa (0,5)(4,5)(?,?)(4,5)
+:HA#100:E X(.?){0,}Y X1234567Y (0,9)(7,8)
+:HA#101:E X(.?){1,}Y X1234567Y (0,9)(7,8)
+:HA#102:E X(.?){2,}Y X1234567Y (0,9)(7,8)
+:HA#103:E X(.?){3,}Y X1234567Y (0,9)(7,8)
+:HA#104:E X(.?){4,}Y X1234567Y (0,9)(7,8)
+:HA#105:E X(.?){5,}Y X1234567Y (0,9)(7,8)
+:HA#106:E X(.?){6,}Y X1234567Y (0,9)(7,8)
+:HA#107:E X(.?){7,}Y X1234567Y (0,9)(7,8)
+:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(7,8)
+:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(7,8)
+:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(7,8)
+:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(7,8)
+:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(7,8)
+:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(7,8)
+:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(7,8)
+:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(7,8)
+:HA#260:E (a|ab|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#261:E (a|ab|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#262:E (a|ab|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#263:E (a|ab|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#266:E (a|ab|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#267:E (a|ab|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#268:E (a|ab|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#270:E (a|ab|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#271:E (a|ab|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
+:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
diff --git a/usr/src/test/libc-tests/tests/regex/data/rightassoc.dat b/usr/src/test/libc-tests/tests/regex/data/rightassoc.dat
new file mode 100644
index 0000000000..ed7f28e621
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/rightassoc.dat
@@ -0,0 +1,16 @@
+NOTE left-assoc:pass-none right-assoc:pass-all : 2002-04-29
+
+E (a|ab)(c|bcd)(d*) abcd (0,4)(0,2)(2,3)(3,4)
+E (a|ab)(bcd|c)(d*) abcd (0,4)(0,2)(2,3)(3,4)
+E (ab|a)(c|bcd)(d*) abcd (0,4)(0,2)(2,3)(3,4)
+E (ab|a)(bcd|c)(d*) abcd (0,4)(0,2)(2,3)(3,4)
+
+E (a*)(b|abc)(c*) abc (0,3)(0,1)(1,2)(2,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,1)(1,2)(2,3)
+E (a*)(b|abc)(c*) abc (0,3)(0,1)(1,2)(2,3)
+E (a*)(abc|b)(c*) abc (0,3)(0,1)(1,2)(2,3)
+
+E (a|ab)(c|bcd)(d|.*) abcd (0,4)(0,2)(2,3)(3,4)
+E (a|ab)(bcd|c)(d|.*) abcd (0,4)(0,2)(2,3)(3,4)
+E (ab|a)(c|bcd)(d|.*) abcd (0,4)(0,2)(2,3)(3,4)
+E (ab|a)(bcd|c)(d|.*) abcd (0,4)(0,2)(2,3)(3,4)
diff --git a/usr/src/test/libc-tests/tests/regex/data/rightassoc.out b/usr/src/test/libc-tests/tests/regex/data/rightassoc.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/data/rightassoc.out
diff --git a/usr/src/test/libc-tests/tests/regex/data/startend.in b/usr/src/test/libc-tests/tests/regex/data/startend.in
deleted file mode 100644
index c396e58ac4..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/startend.in
+++ /dev/null
@@ -1,9 +0,0 @@
-# check out the STARTEND option
-[abc] &# a(b)c b
-[abc] &# a(d)c
-[abc] &# a(bc)d b
-[abc] &# a(dc)d c
-. &# a()c
-b.*c &# b(bc)c bc
-b.* &# b(bc)c bc
-.*c &# b(bc)c bc
diff --git a/usr/src/test/libc-tests/tests/regex/data/subexp.in b/usr/src/test/libc-tests/tests/regex/data/subexp.in
deleted file mode 100644
index c7bcc06175..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/subexp.in
+++ /dev/null
@@ -1,57 +0,0 @@
-# subexpressions
-a(b)(c)d - abcd abcd b,c
-a(((b)))c - abc abc b,b,b
-a(b|(c))d - abd abd b,-
-a(b*|c|e)d - abbd abbd bb
-a(b*|c|e)d - acd acd c
-a(b*|c|e)d - ad ad @d
-a(b?)c - abc abc b
-a(b?)c - ac ac @c
-a(b+)c - abc abc b
-a(b+)c - abbbc abbbc bbb
-a(b*)c - ac ac @c
-(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
-# the regression tester only asks for 9 subexpressions
-a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
-a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
-a([bc]?)c - abc abc b
-a([bc]?)c - ac ac @c
-a([bc]+)c - abc abc b
-a([bc]+)c - abcc abcc bc
-a([bc]+)bc - abcbc abcbc bc
-a(bb+|b)b - abb abb b
-a(bbb+|bb+|b)b - abb abb b
-a(bbb+|bb+|b)b - abbb abbb bb
-a(bbb+|bb+|b)bb - abbb abbb b
-(.*).* - abcdef abcdef abcdef
-(a*)* - bc @b @b
-
-# do we get the right subexpression when it is used more than once?
-a(b|c)*d - ad ad -
-a(b|c)*d - abcd abcd c
-a(b|c)+d - abd abd b
-a(b|c)+d - abcd abcd c
-a(b|c?)+d - ad ad @d
-a(b|c?)+d - abcd abcd @d
-a(b|c){0,0}d - ad ad -
-a(b|c){0,1}d - ad ad -
-a(b|c){0,1}d - abd abd b
-a(b|c){0,2}d - ad ad -
-a(b|c){0,2}d - abcd abcd c
-a(b|c){0,}d - ad ad -
-a(b|c){0,}d - abcd abcd c
-a(b|c){1,1}d - abd abd b
-a(b|c){1,1}d - acd acd c
-a(b|c){1,2}d - abd abd b
-a(b|c){1,2}d - abcd abcd c
-a(b|c){1,}d - abd abd b
-a(b|c){1,}d - abcd abcd c
-a(b|c){2,2}d - acbd acbd b
-a(b|c){2,2}d - abcd abcd c
-a(b|c){2,4}d - abcd abcd c
-a(b|c){2,4}d - abcbd abcbd b
-a(b|c){2,4}d - abcbcd abcbcd c
-a(b|c){2,}d - abcd abcd c
-a(b|c){2,}d - abcbd abcbd b
-a(b+|((c)*))+d - abd abd @d,@d,-
-a(b+|((c)*))+d - abcd abcd @d,@d,-
diff --git a/usr/src/test/libc-tests/tests/regex/data/subtle.in b/usr/src/test/libc-tests/tests/regex/data/subtle.in
deleted file mode 100644
index 92d68bb9c2..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/subtle.in
+++ /dev/null
@@ -1,21 +0,0 @@
-# subtleties of matching
-abc & xabcy abc
-a\(b\)?c\1d b acd
-aBc i Abc Abc
-a[Bc]*d i abBCcd abBCcd
-0[[:upper:]]1 &i 0a1 0a1
-0[[:lower:]]1 &i 0A1 0A1
-a[^b]c &i abc
-a[^b]c &i aBc
-a[^b]c &i adc adc
-[a]b[c] - abc abc
-[a]b[a] - aba aba
-[abc]b[abc] - abc abc
-[abc]b[abd] - abd abd
-a(b?c)+d - accd accd
-(wee|week)(knights|night) - weeknights weeknights
-(we|wee|week|frob)(knights|night|day) - weeknights weeknights
-a[bc]d - xyzaaabcaababdacd abd
-a[ab]c - aaabc abc
-abc s abc abc
-a* & b @b
diff --git a/usr/src/test/libc-tests/tests/regex/data/word_bound.in b/usr/src/test/libc-tests/tests/regex/data/word_bound.in
deleted file mode 100644
index e09a329afd..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/word_bound.in
+++ /dev/null
@@ -1,13 +0,0 @@
-# word boundaries (ick)
-[[:<:]]a & a a
-[[:<:]]a & ba
-[[:<:]]a & -a a
-a[[:>:]] & a a
-a[[:>:]] & ab
-a[[:>:]] & a- a
-[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
-[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
-[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
-[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc
-[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_
-[[:<:]]a_b[[:>:]] & x_a_b
diff --git a/usr/src/test/libc-tests/tests/regex/data/zero.in b/usr/src/test/libc-tests/tests/regex/data/zero.in
deleted file mode 100644
index 2786944eb2..0000000000
--- a/usr/src/test/libc-tests/tests/regex/data/zero.in
+++ /dev/null
@@ -1,7 +0,0 @@
-# cases involving NULs
-aZb & a a
-aZb &p a
-aZb &p# (aZb) aZb
-aZ*b &p# (ab) ab
-a.b &# (aZb) aZb
-a.* &# (aZb)c aZb
diff --git a/usr/src/test/libc-tests/tests/regex/main.c b/usr/src/test/libc-tests/tests/regex/main.c
deleted file mode 100644
index fa7a2dd408..0000000000
--- a/usr/src/test/libc-tests/tests/regex/main.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright (c) 1993 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-
-#include "test_regex.h"
-
-char *progname;
-int line = 0;
-int status = 0;
-
-int copts = REG_EXTENDED;
-int eopts = 0;
-regoff_t startoff = 0;
-regoff_t endoff = 0;
-
-static char empty = '\0';
-
-static char *eprint(int);
-static int efind(char *);
-
-/*
- * main - do the simple case, hand off to regress() for regression
- */
-int
-main(int argc, char *argv[])
-{
- regex_t re;
-#define NS 10
- regmatch_t subs[NS];
- char erbuf[100];
- int err;
- size_t len;
- int c;
- int errflg = 0;
- int i;
- extern int optind;
- extern char *optarg;
-
- progname = argv[0];
-
- while ((c = getopt(argc, argv, "c:e:S:E:")) != -1)
- switch (c) {
- case 'c': /* compile options */
- copts = options('c', optarg);
- break;
- case 'e': /* execute options */
- eopts = options('e', optarg);
- break;
- case 'S': /* start offset */
- startoff = (regoff_t)atoi(optarg);
- break;
- case 'E': /* end offset */
- endoff = (regoff_t)atoi(optarg);
- break;
- case '?':
- default:
- errflg++;
- break;
- }
- if (errflg) {
- fprintf(stderr, "usage: %s ", progname);
- fprintf(stderr, "[-c copt][-C][-d] [re]\n");
- exit(2);
- }
-
- if (optind >= argc) {
- regress(stdin);
- exit(status);
- }
-
- err = regcomp(&re, argv[optind++], copts);
- if (err) {
- len = regerror(err, &re, erbuf, sizeof (erbuf));
- fprintf(stderr, "error %s, %zd/%zd `%s'\n",
- eprint(err), len, (size_t)sizeof (erbuf), erbuf);
- exit(status);
- }
-
- if (optind >= argc) {
- regfree(&re);
- exit(status);
- }
-
- if (eopts&REG_STARTEND) {
- subs[0].rm_so = startoff;
- subs[0].rm_eo = strlen(argv[optind]) - endoff;
- }
- err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
- if (err) {
- len = regerror(err, &re, erbuf, sizeof (erbuf));
- fprintf(stderr, "error %s, %zd/%zd `%s'\n",
- eprint(err), len, (size_t)sizeof (erbuf), erbuf);
- exit(status);
- }
- if (!(copts&REG_NOSUB)) {
- len = (int)(subs[0].rm_eo - subs[0].rm_so);
- if (subs[0].rm_so != -1) {
- if (len != 0) {
- printf("match `%.*s'\n", (int)len,
- argv[optind] + subs[0].rm_so);
- } else {
- printf("match `'@%.1s\n",
- argv[optind] + subs[0].rm_so);
- }
- }
- for (i = 1; i < NS; i++) {
- if (subs[i].rm_so != -1) {
- printf("(%d) `%.*s'\n", i,
- (int)(subs[i].rm_eo - subs[i].rm_so),
- argv[optind] + subs[i].rm_so);
- }
- }
- }
- exit(status);
-}
-
-/*
- * regress - main loop of regression test
- */
-void
-regress(FILE *in)
-{
- char inbuf[1000];
-#define MAXF 10
- char *f[MAXF];
- int nf;
- int i;
- char erbuf[100];
- size_t ne;
- const char *badpat = "invalid regular expression";
-#define SHORT 10
- const char *bpname = "REG_BADPAT";
- regex_t re;
-
- while (fgets(inbuf, sizeof (inbuf), in) != NULL) {
- line++;
- if (inbuf[0] == '#' || inbuf[0] == '\n')
- continue; /* NOTE CONTINUE */
- inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
- nf = split(inbuf, f, MAXF, "\t\t");
- if (nf < 3) {
- fprintf(stderr, "bad input, line %d\n", line);
- exit(1);
- }
- for (i = 0; i < nf; i++)
- if (strcmp(f[i], "\"\"") == 0)
- f[i] = &empty;
- if (nf <= 3)
- f[3] = NULL;
- if (nf <= 4)
- f[4] = NULL;
- try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
- if (opt('&', f[1])) /* try with either type of RE */
- try(f[0], f[1], f[2], f[3], f[4],
- options('c', f[1]) &~ REG_EXTENDED);
- }
-
- ne = regerror(REG_BADPAT, NULL, erbuf, sizeof (erbuf));
- if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
- fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
- erbuf, badpat);
- status = 1;
- }
- ne = regerror(REG_BADPAT, NULL, erbuf, (size_t)SHORT);
- if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
- ne != strlen(badpat)+1) {
- fprintf(stderr,
- "end: regerror() short test gave `%s' not `%.*s'\n",
- erbuf, SHORT-1, badpat);
- status = 1;
- }
- ne = regerror(REG_ITOA|REG_BADPAT, NULL, erbuf, sizeof (erbuf));
- if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
- fprintf(stderr,
- "end: regerror() ITOA test gave `%s' not `%s'\n",
- erbuf, bpname);
- status = 1;
- }
- re.re_endp = bpname;
- ne = regerror(REG_ATOI, &re, erbuf, sizeof (erbuf));
- if (atoi(erbuf) != (int)REG_BADPAT) {
- fprintf(stderr,
- "end: regerror() ATOI test gave `%s' not `%ld'\n",
- erbuf, (long)REG_BADPAT);
- status = 1;
- } else if (ne != strlen(erbuf)+1) {
- fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
- erbuf, (long)REG_BADPAT);
- status = 1;
- }
-}
-
-/*
- * try - try it, and report on problems
- */
-void
-try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
-{
- regex_t re;
-#define NSUBS 10
- regmatch_t subs[NSUBS];
-#define NSHOULD 15
- char *should[NSHOULD];
- int nshould;
- char erbuf[100];
- int err;
- int len;
- const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
- int i;
- char *grump;
- char f0copy[1000];
- char f2copy[1000];
-
- strcpy(f0copy, f0);
- re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
- fixstr(f0copy);
- err = regcomp(&re, f0copy, opts);
- if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
- /* unexpected error or wrong error */
- len = regerror(err, &re, erbuf, sizeof (erbuf));
- fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
- line, type, eprint(err), len, (int)sizeof (erbuf), erbuf);
- status = 1;
- } else if (err == 0 && opt('C', f1)) {
- /* unexpected success */
- fprintf(stderr, "%d: %s should have given REG_%s\n",
- line, type, f2);
- status = 1;
- err = 1; /* so we won't try regexec */
- }
-
- if (err != 0) {
- regfree(&re);
- return;
- }
-
- strcpy(f2copy, f2);
- fixstr(f2copy);
-
- if (options('e', f1)&REG_STARTEND) {
- if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
- fprintf(stderr, "%d: bad STARTEND syntax\n", line);
- subs[0].rm_so = strchr(f2, '(') - f2 + 1;
- subs[0].rm_eo = strchr(f2, ')') - f2;
- }
- err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
-
- if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
- /* unexpected error or wrong error */
- len = regerror(err, &re, erbuf, sizeof (erbuf));
- fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
- line, type, eprint(err), len, (int)sizeof (erbuf), erbuf);
- status = 1;
- } else if (err != 0) {
- /* nothing more to check */
- } else if (f3 == NULL) {
- /* unexpected success */
- fprintf(stderr, "%d: %s exec should have failed\n", line, type);
- status = 1;
- err = 1; /* just on principle */
- } else if (opts&REG_NOSUB) {
- /* nothing more to check */
- } else if ((grump = check(f2, subs[0], f3)) != NULL) {
- fprintf(stderr, "%d: %s %s\n", line, type, grump);
- status = 1;
- err = 1;
- }
-
- if (err != 0 || f4 == NULL) {
- regfree(&re);
- return;
- }
-
- for (i = 1; i < NSHOULD; i++)
- should[i] = NULL;
- nshould = split(f4, &should[1], NSHOULD-1, ",");
- if (nshould == 0) {
- nshould = 1;
- should[1] = &empty;
- }
- for (i = 1; i < NSUBS; i++) {
- grump = check(f2, subs[i], should[i]);
- if (grump != NULL) {
- fprintf(stderr, "%d: %s $%d %s\n", line,
- type, i, grump);
- status = 1;
- err = 1;
- }
- }
-
- regfree(&re);
-}
-
-/*
- * options - pick options out of a regression-test string
- */
-int
-options(int type, char *s)
-{
- char *p;
- int o = (type == 'c') ? copts : eopts;
- const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
-
- for (p = s; *p != '\0'; p++)
- if (strchr(legal, *p) != NULL)
- switch (*p) {
- case 'b':
- o &= ~REG_EXTENDED;
- break;
- case 'i':
- o |= REG_ICASE;
- break;
- case 's':
- o |= REG_NOSUB;
- break;
- case 'n':
- o |= REG_NEWLINE;
- break;
- case 'm':
- o &= ~REG_EXTENDED;
- o |= REG_NOSPEC;
- break;
- case 'p':
- o |= REG_PEND;
- break;
- case '^':
- o |= REG_NOTBOL;
- break;
- case '$':
- o |= REG_NOTEOL;
- break;
- case '#':
- o |= REG_STARTEND;
- break;
- case 't': /* trace */
- o |= REG_TRACE;
- break;
- case 'l': /* force long representation */
- o |= REG_LARGE;
- break;
- case 'r': /* force backref use */
- o |= REG_BACKR;
- break;
- }
- return (o);
-}
-
-/*
- * opt - is a particular option in a regression string?
- */
-int /* predicate */
-opt(int c, char *s)
-{
- return (strchr(s, c) != NULL);
-}
-
-/*
- * fixstr - transform magic characters in strings
- */
-void
-fixstr(char *p)
-{
- if (p == NULL)
- return;
-
- for (; *p != '\0'; p++)
- if (*p == 'N')
- *p = '\n';
- else if (*p == 'T')
- *p = '\t';
- else if (*p == 'S')
- *p = ' ';
- else if (*p == 'Z')
- *p = '\0';
-}
-
-/*
- * check - check a substring match
- */
-char *
-check(char *str, regmatch_t sub, char *should)
-{
- int len;
- int shlen;
- char *p;
- static char grump[500];
- char *at = NULL;
-
- if (should != NULL && strcmp(should, "-") == 0)
- should = NULL;
- if (should != NULL && should[0] == '@') {
- at = should + 1;
- should = &empty;
- }
-
- /* check rm_so and rm_eo for consistency */
- if ((sub.rm_so > sub.rm_eo) ||
- (sub.rm_so == -1 && sub.rm_eo != -1) ||
- (sub.rm_so != -1 && sub.rm_eo == -1) ||
- (sub.rm_so != -1 && sub.rm_so < 0) ||
- (sub.rm_eo != -1 && sub.rm_eo < 0)) {
- sprintf(grump, "start %ld end %ld",
- (long)sub.rm_so, (long)sub.rm_eo);
- return (grump);
- }
-
- /* check for no match */
- if (sub.rm_so == -1) {
- if (should == NULL)
- return (NULL);
- else {
- sprintf(grump, "did not match");
- return (grump);
- }
- }
-
- /* check for in range */
- if (sub.rm_eo > (ssize_t)strlen(str)) {
- sprintf(grump, "start %ld end %ld, past end of string",
- (long)sub.rm_so, (long)sub.rm_eo);
- return (grump);
- }
-
- len = (int)(sub.rm_eo - sub.rm_so);
- p = str + sub.rm_so;
-
- /* check for not supposed to match */
- if (should == NULL) {
- sprintf(grump, "matched `%.*s'", len, p);
- return (grump);
- }
-
- /* check for wrong match */
- shlen = (int)strlen(should);
- if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
- sprintf(grump, "matched `%.*s' instead", len, p);
- return (grump);
- }
- if (shlen > 0)
- return (NULL);
-
- /* check null match in right place */
- if (at == NULL)
- return (NULL);
- shlen = strlen(at);
- if (shlen == 0)
- shlen = 1; /* force check for end-of-string */
- if (strncmp(p, at, shlen) != 0) {
- sprintf(grump, "matched null at `%.20s'", p);
- return (grump);
- }
- return (NULL);
-}
-
-/*
- * eprint - convert error number to name
- */
-static char *
-eprint(int err)
-{
- static char epbuf[100];
- size_t len;
-
- len = regerror(REG_ITOA|err, NULL, epbuf, sizeof (epbuf));
- assert(len <= sizeof (epbuf));
- return (epbuf);
-}
-
-/*
- * efind - convert error name to number
- */
-static int
-efind(char *name)
-{
- static char efbuf[100];
- regex_t re;
-
- sprintf(efbuf, "REG_%s", name);
- assert(strlen(efbuf) < sizeof (efbuf));
- re.re_endp = efbuf;
- (void) regerror(REG_ATOI, &re, efbuf, sizeof (efbuf));
- return (atoi(efbuf));
-}
diff --git a/usr/src/test/libc-tests/tests/regex/t_regex.sh b/usr/src/test/libc-tests/tests/regex/regex_test.sh
index 990f13154c..e00a243b53 100644
--- a/usr/src/test/libc-tests/tests/regex/t_regex.sh
+++ b/usr/src/test/libc-tests/tests/regex/regex_test.sh
@@ -12,14 +12,17 @@
#
#
-# Copyright 2017 Nexenta Systems, Inc.
+# Copyright 2018 Nexenta Systems, Inc.
#
TESTDIR=$(dirname $0)
-HREGEX=${TESTDIR}/h_regex
+TREGEX=${TESTDIR}/testregex
-for t in $TESTDIR/data/*.in; do
- $HREGEX < $t || exit 1
- $HREGEX -el < $t || exit 1
- $HREGEX -er < $t || exit 1
+for t in basic categorize forcedassoc leftassoc \
+ nullsubexpr repetition rightassoc; do
+ ${TREGEX} -F ${TESTDIR}/data/${t}.dat | \
+ diff -u - ${TESTDIR}/data/${t}.out || \
+ exit 1
done
+
+exit 0
diff --git a/usr/src/test/libc-tests/tests/regex/split.c b/usr/src/test/libc-tests/tests/regex/split.c
deleted file mode 100644
index 664b8375af..0000000000
--- a/usr/src/test/libc-tests/tests/regex/split.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 1993 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <regex.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "test_regex.h"
-
-/*
- * split - divide a string into fields, like awk split()
- *
- * returns number of fields, including overflow
- *
- * fields[] list is not NULL-terminated
- * nfields number of entries available in fields[]
- * sep "" white, "c" single char, "ab" [ab]+
- */
-int
-split(char *string, char *fields[], int nfields, const char *sep)
-{
- char *p = string;
- char c; /* latest character */
- char sepc = *sep;
- char sepc2;
- int fn;
- char **fp = fields;
- const char *sepp;
- int trimtrail;
-
- /* white space */
- if (sepc == '\0') {
- while ((c = *p++) == ' ' || c == '\t')
- continue;
- p--;
- trimtrail = 1;
- sep = " \t"; /* note, code below knows this is 2 long */
- sepc = ' ';
- } else
- trimtrail = 0;
- sepc2 = sep[1]; /* now we can safely pick this up */
-
- /* catch empties */
- if (*p == '\0')
- return (0);
-
- /* single separator */
- if (sepc2 == '\0') {
- fn = nfields;
- for (;;) {
- *fp++ = p;
- fn--;
- if (fn == 0)
- break;
- while ((c = *p++) != sepc)
- if (c == '\0')
- return (nfields - fn);
- *(p-1) = '\0';
- }
- /* we have overflowed the fields vector -- just count them */
- fn = nfields;
- for (;;) {
- while ((c = *p++) != sepc)
- if (c == '\0')
- return (fn);
- fn++;
- }
- /* not reached */
- }
-
- /* two separators */
- if (sep[2] == '\0') {
- fn = nfields;
- for (;;) {
- *fp++ = p;
- fn--;
- while ((c = *p++) != sepc && c != sepc2)
- if (c == '\0') {
- if (trimtrail && **(fp-1) == '\0')
- fn++;
- return (nfields - fn);
- }
- if (fn == 0)
- break;
- *(p-1) = '\0';
- while ((c = *p++) == sepc || c == sepc2)
- continue;
- p--;
- }
- /* we have overflowed the fields vector -- just count them */
- fn = nfields;
- while (c != '\0') {
- while ((c = *p++) == sepc || c == sepc2)
- continue;
- p--;
- fn++;
- while ((c = *p++) != '\0' && c != sepc && c != sepc2)
- continue;
- }
- /* might have to trim trailing white space */
- if (trimtrail) {
- p--;
- while ((c = *--p) == sepc || c == sepc2)
- continue;
- p++;
- if (*p != '\0') {
- if (fn == nfields+1)
- *p = '\0';
- fn--;
- }
- }
- return (fn);
- }
-
- /* n separators */
- fn = 0;
- for (;;) {
- if (fn < nfields)
- *fp++ = p;
- fn++;
- for (;;) {
- c = *p++;
- if (c == '\0')
- return (fn);
- sepp = sep;
- while ((sepc = *sepp++) != '\0' && sepc != c)
- continue;
- if (sepc != '\0') /* it was a separator */
- break;
- }
- if (fn < nfields)
- *(p-1) = '\0';
- for (;;) {
- c = *p++;
- sepp = sep;
- while ((sepc = *sepp++) != '\0' && sepc != c)
- continue;
- if (sepc == '\0') /* it wasn't a separator */
- break;
- }
- p--;
- }
-
- /* not reached */
-}
diff --git a/usr/src/test/libc-tests/tests/regex/test_regex.h b/usr/src/test/libc-tests/tests/regex/test_regex.h
deleted file mode 100644
index 7a90ac4859..0000000000
--- a/usr/src/test/libc-tests/tests/regex/test_regex.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2011 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* from main.c */
-void regress(FILE *);
-void try(char *, char *, char *, char *, char *, int);
-int options(int, char *);
-int opt(int, char *);
-void fixstr(char *);
-char *check(char *, regmatch_t, char *);
-
-/* from split.c */
-int split(char *string, char *fields[], int nfields, const char *sep);
diff --git a/usr/src/test/libc-tests/tests/regex/testregex.c b/usr/src/test/libc-tests/tests/regex/testregex.c
new file mode 100644
index 0000000000..0dd7b64680
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/regex/testregex.c
@@ -0,0 +1,2286 @@
+#pragma prototyped noticed
+
+/*
+ * regex(3) test harness
+ *
+ * build: cc -o testregex testregex.c
+ * help: testregex --man
+ * note: REG_* features are detected by #ifdef; if REG_* are enums
+ * then supply #define REG_foo REG_foo for each enum REG_foo
+ *
+ * Glenn Fowler <glenn.s.fowler@gmail.com>
+ * AT&T Research
+ *
+ * PLEASE: publish your tests so everyone can benefit
+ *
+ * The following license covers testregex.c and all associated test data.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following disclaimer:
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2010-06-10 $\0\n";
+
+#if _PACKAGE_ast
+#include <ast.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#include <regex.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+#ifndef RE_DUP_MAX
+#define RE_DUP_MAX 32767
+#endif
+
+#if !_PACKAGE_ast
+#undef REG_DISCIPLINE
+#endif
+
+#ifndef REG_DELIMITED
+#undef _REG_subcomp
+#endif
+
+#define TEST_ARE 0x00000001
+#define TEST_BRE 0x00000002
+#define TEST_ERE 0x00000004
+#define TEST_KRE 0x00000008
+#define TEST_LRE 0x00000010
+#define TEST_SRE 0x00000020
+
+#define TEST_EXPAND 0x00000100
+#define TEST_LENIENT 0x00000200
+
+#define TEST_QUERY 0x00000400
+#define TEST_SUB 0x00000800
+#define TEST_UNSPECIFIED 0x00001000
+#define TEST_VERIFY 0x00002000
+#define TEST_AND 0x00004000
+#define TEST_OR 0x00008000
+
+#define TEST_DELIMIT 0x00010000
+#define TEST_OK 0x00020000
+#define TEST_SAME 0x00040000
+
+#define TEST_ACTUAL 0x00100000
+#define TEST_BASELINE 0x00200000
+#define TEST_FAIL 0x00400000
+#define TEST_PASS 0x00800000
+#define TEST_SUMMARY 0x01000000
+
+#define TEST_IGNORE_ERROR 0x02000000
+#define TEST_IGNORE_OVER 0x04000000
+#define TEST_IGNORE_POSITION 0x08000000
+
+#define TEST_CATCH 0x10000000
+#define TEST_VERBOSE 0x20000000
+
+#define TEST_DECOMP 0x40000000
+
+#define TEST_GLOBAL (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
+
+#ifdef REG_DISCIPLINE
+
+
+#include <stk.h>
+
+typedef struct Disc_s
+{
+ regdisc_t disc;
+ int ordinal;
+ Sfio_t* sp;
+} Disc_t;
+
+static void*
+compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
+{
+ Disc_t* dp = (Disc_t*)disc;
+
+ return (void*)((char*)0 + ++dp->ordinal);
+}
+
+static int
+execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
+{
+ Disc_t* dp = (Disc_t*)disc;
+
+ sfprintf(dp->sp, "{%-.*s}(%lu:%d)", xlen, xstr, (char*)data - (char*)0, slen);
+ return atoi(xstr);
+}
+
+static void*
+resizef(void* handle, void* data, size_t size)
+{
+ if (!size)
+ return 0;
+ return stkalloc((Sfio_t*)handle, size);
+}
+
+#endif
+
+#ifndef NiL
+#ifdef __STDC__
+#define NiL 0
+#else
+#define NiL (char*)0
+#endif
+#endif
+
+#define H(x) do{if(html)fprintf(stderr,x);}while(0)
+#define T(x) fprintf(stderr,x)
+
+static void
+help(int html)
+{
+H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
+H("<HTML>\n");
+H("<HEAD>\n");
+H("<TITLE>testregex man document</TITLE>\n");
+H("</HEAD>\n");
+H("<BODY bgcolor=white>\n");
+H("<PRE>\n");
+T("NAME\n");
+T(" testregex - regex(3) test harness\n");
+T("\n");
+T("SYNOPSIS\n");
+T(" testregex [ options ]\n");
+T("\n");
+T("DESCRIPTION\n");
+T(" testregex reads regex(3) test specifications, one per line, from the\n");
+T(" standard input and writes one output line for each failed test. A\n");
+T(" summary line is written after all tests are done. Each successful\n");
+T(" test is run again with REG_NOSUB. Unsupported features are noted\n");
+T(" before the first test, and tests requiring these features are\n");
+T(" silently ignored.\n");
+T("\n");
+T("OPTIONS\n");
+T(" -c catch signals and non-terminating calls\n");
+T(" -e ignore error return mismatches\n");
+T(" -h list help on standard error\n");
+T(" -n do not repeat successful tests with regnexec()\n");
+T(" -o ignore match[] overrun errors\n");
+T(" -p ignore negative position mismatches\n");
+T(" -s use stack instead of malloc\n");
+T(" -x do not repeat successful tests with REG_NOSUB\n");
+T(" -v list each test line\n");
+T(" -A list failed test lines with actual answers\n");
+T(" -B list all test lines with actual answers\n");
+T(" -F list failed test lines\n");
+T(" -P list passed test lines\n");
+T(" -S output one summary line\n");
+T("\n");
+T("INPUT FORMAT\n");
+T(" Input lines may be blank, a comment beginning with #, or a test\n");
+T(" specification. A specification is five fields separated by one\n");
+T(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
+T(" 0 pointer.\n");
+T("\n");
+T(" Field 1: the regex(3) flags to apply, one character per REG_feature\n");
+T(" flag. The test is skipped if REG_feature is not supported by the\n");
+T(" implementation. If the first character is not [BEASKLP] then the\n");
+T(" specification is a global control line. One or more of [BEASKLP] may be\n");
+T(" specified; the test will be repeated for each mode.\n");
+T("\n");
+T(" B basic BRE (grep, ed, sed)\n");
+T(" E REG_EXTENDED ERE (egrep)\n");
+T(" A REG_AUGMENTED ARE (egrep with negation)\n");
+T(" S REG_SHELL SRE (sh glob)\n");
+T(" K REG_SHELL|REG_AUGMENTED KRE (ksh glob)\n");
+T(" L REG_LITERAL LRE (fgrep)\n");
+T("\n");
+T(" a REG_LEFT|REG_RIGHT implicit ^...$\n");
+T(" b REG_NOTBOL lhs does not match ^\n");
+T(" c REG_COMMENT ignore space and #...\\n\n");
+T(" d REG_SHELL_DOT explicit leading . match\n");
+T(" e REG_NOTEOL rhs does not match $\n");
+T(" f REG_MULTIPLE multiple \\n separated patterns\n");
+T(" g FNM_LEADING_DIR testfnmatch only -- match until /\n");
+T(" h REG_MULTIREF multiple digit backref\n");
+T(" i REG_ICASE ignore case\n");
+T(" j REG_SPAN . matches \\n\n");
+T(" k REG_ESCAPE \\ to ecape [...] delimiter\n");
+T(" l REG_LEFT implicit ^...\n");
+T(" m REG_MINIMAL minimal match\n");
+T(" n REG_NEWLINE explicit \\n match\n");
+T(" o REG_ENCLOSED (|&) magic inside [@|&](...)\n");
+T(" p REG_SHELL_PATH explicit / match\n");
+T(" q REG_DELIMITED delimited pattern\n");
+T(" r REG_RIGHT implicit ...$\n");
+T(" s REG_SHELL_ESCAPED \\ not special\n");
+T(" t REG_MUSTDELIM all delimiters must be specified\n");
+T(" u standard unspecified behavior -- errors not counted\n");
+T(" v REG_CLASS_ESCAPE \\ special inside [...]\n");
+T(" w REG_NOSUB no subexpression match array\n");
+T(" x REG_LENIENT let some errors slide\n");
+T(" y REG_LEFT regexec() implicit ^...\n");
+T(" z REG_NULL NULL subexpressions ok\n");
+T(" $ expand C \\c escapes in fields 2 and 3\n");
+T(" / field 2 is a regsubcomp() expression\n");
+T(" = field 3 is a regdecomp() expression\n");
+T("\n");
+T(" Field 1 control lines:\n");
+T("\n");
+T(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
+T("\n");
+T(" ?test ... output field 5 if passed and != EXPECTED, silent otherwise\n");
+T(" &test ... output field 5 if current and previous passed\n");
+T(" |test ... output field 5 if current passed and previous failed\n");
+T(" ; ... output field 2 if previous failed\n");
+T(" {test ... skip if failed until }\n");
+T(" } end of skip\n");
+T("\n");
+T(" : comment comment copied as output NOTE\n");
+T(" :comment:test :comment: ignored\n");
+T(" N[OTE] comment comment copied as output NOTE\n");
+T(" T[EST] comment comment\n");
+T("\n");
+T(" number use number for nmatch (20 by default)\n");
+T("\n");
+T(" Field 2: the regular expression pattern; SAME uses the pattern from\n");
+T(" the previous specification. RE_DUP_MAX inside {...} expands to the\n");
+T(" value from <limits.h>.\n");
+T("\n");
+T(" Field 3: the string to match. X...{RE_DUP_MAX} expands to RE_DUP_MAX\n");
+T(" copies of X.\n");
+T("\n");
+T(" Field 4: the test outcome. This is either one of the posix error\n");
+T(" codes (with REG_ omitted) or the match array, a list of (m,n)\n");
+T(" entries with m and n being first and last+1 positions in the\n");
+T(" field 3 string, or NULL if REG_NOSUB is in effect and success\n");
+T(" is expected. BADPAT is acceptable in place of any regcomp(3)\n");
+T(" error code. The match[] array is initialized to (-2,-2) before\n");
+T(" each test. All array elements from 0 to nmatch-1 must be specified\n");
+T(" in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
+T(" Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
+T(" matched (?{...}) expression, where x is the text enclosed by {...},\n");
+T(" o is the expression ordinal counting from 1, and n is the length of\n");
+T(" the unmatched portion of the subject string. If x starts with a\n");
+T(" number then that is the return value of re_execf(), otherwise 0 is\n");
+T(" returned. RE_DUP_MAX[-+]N expands to the <limits.h> value -+N.\n");
+T("\n");
+T(" Field 5: optional comment appended to the report.\n");
+T("\n");
+T("CAVEAT\n");
+T(" If a regex implementation misbehaves with memory then all bets are off.\n");
+T("\n");
+T("CONTRIBUTORS\n");
+T(" Glenn Fowler glenn.s.fowler@gmail.com (ksh strmatch, regex extensions)\n");
+T(" David Korn dgkorn@gmail.com (ksh glob matcher)\n");
+T(" Doug McIlroy mcilroy@dartmouth.edu (ast regex/testre in C++)\n");
+T(" Tom Lord lord@regexps.com (rx tests)\n");
+T(" Henry Spencer henry@zoo.toronto.edu (original public regex)\n");
+T(" Andrew Hume andrew@research.att.com (gre tests)\n");
+T(" John Maddock John_Maddock@compuserve.com (regex++ tests)\n");
+T(" Philip Hazel ph10@cam.ac.uk (pcre tests)\n");
+T(" Ville Laurikari vl@iki.fi (libtre tests)\n");
+H("</PRE>\n");
+H("</BODY>\n");
+H("</HTML>\n");
+}
+
+#ifndef elementsof
+#define elementsof(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+#ifndef streq
+#define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
+#endif
+
+#define HUNG 2
+#define NOTEST (~0)
+
+#ifndef REG_TEST_DEFAULT
+#define REG_TEST_DEFAULT 0
+#endif
+
+#ifndef REG_EXEC_DEFAULT
+#define REG_EXEC_DEFAULT 0
+#endif
+
+static const char* unsupported[] =
+{
+ "BASIC",
+#ifndef REG_EXTENDED
+ "EXTENDED",
+#endif
+#ifndef REG_AUGMENTED
+ "AUGMENTED",
+#endif
+#ifndef REG_SHELL
+ "SHELL",
+#endif
+
+#ifndef REG_CLASS_ESCAPE
+ "CLASS_ESCAPE",
+#endif
+#ifndef REG_COMMENT
+ "COMMENT",
+#endif
+#ifndef REG_DELIMITED
+ "DELIMITED",
+#endif
+#ifndef REG_DISCIPLINE
+ "DISCIPLINE",
+#endif
+#ifndef REG_ESCAPE
+ "ESCAPE",
+#endif
+#ifndef REG_ICASE
+ "ICASE",
+#endif
+#ifndef REG_LEFT
+ "LEFT",
+#endif
+#ifndef REG_LENIENT
+ "LENIENT",
+#endif
+#ifndef REG_LITERAL
+ "LITERAL",
+#endif
+#ifndef REG_MINIMAL
+ "MINIMAL",
+#endif
+#ifndef REG_MULTIPLE
+ "MULTIPLE",
+#endif
+#ifndef REG_MULTIREF
+ "MULTIREF",
+#endif
+#ifndef REG_MUSTDELIM
+ "MUSTDELIM",
+#endif
+#ifndef REG_NEWLINE
+ "NEWLINE",
+#endif
+#ifndef REG_NOTBOL
+ "NOTBOL",
+#endif
+#ifndef REG_NOTEOL
+ "NOTEOL",
+#endif
+#ifndef REG_NULL
+ "NULL",
+#endif
+#ifndef REG_RIGHT
+ "RIGHT",
+#endif
+#ifndef REG_SHELL_DOT
+ "SHELL_DOT",
+#endif
+#ifndef REG_SHELL_ESCAPED
+ "SHELL_ESCAPED",
+#endif
+#ifndef REG_SHELL_GROUP
+ "SHELL_GROUP",
+#endif
+#ifndef REG_SHELL_PATH
+ "SHELL_PATH",
+#endif
+#ifndef REG_SPAN
+ "SPAN",
+#endif
+#if REG_NOSUB & REG_TEST_DEFAULT
+ "SUBMATCH",
+#endif
+#if !_REG_nexec
+ "regnexec",
+#endif
+#if !_REG_subcomp
+ "regsubcomp",
+#endif
+#if !_REG_decomp
+ "redecomp",
+#endif
+ 0
+};
+
+#ifndef REG_CLASS_ESCAPE
+#define REG_CLASS_ESCAPE NOTEST
+#endif
+#ifndef REG_COMMENT
+#define REG_COMMENT NOTEST
+#endif
+#ifndef REG_DELIMITED
+#define REG_DELIMITED NOTEST
+#endif
+#ifndef REG_ESCAPE
+#define REG_ESCAPE NOTEST
+#endif
+#ifndef REG_ICASE
+#define REG_ICASE NOTEST
+#endif
+#ifndef REG_LEFT
+#define REG_LEFT NOTEST
+#endif
+#ifndef REG_LENIENT
+#define REG_LENIENT 0
+#endif
+#ifndef REG_MINIMAL
+#define REG_MINIMAL NOTEST
+#endif
+#ifndef REG_MULTIPLE
+#define REG_MULTIPLE NOTEST
+#endif
+#ifndef REG_MULTIREF
+#define REG_MULTIREF NOTEST
+#endif
+#ifndef REG_MUSTDELIM
+#define REG_MUSTDELIM NOTEST
+#endif
+#ifndef REG_NEWLINE
+#define REG_NEWLINE NOTEST
+#endif
+#ifndef REG_NOTBOL
+#define REG_NOTBOL NOTEST
+#endif
+#ifndef REG_NOTEOL
+#define REG_NOTEOL NOTEST
+#endif
+#ifndef REG_NULL
+#define REG_NULL NOTEST
+#endif
+#ifndef REG_RIGHT
+#define REG_RIGHT NOTEST
+#endif
+#ifndef REG_SHELL_DOT
+#define REG_SHELL_DOT NOTEST
+#endif
+#ifndef REG_SHELL_ESCAPED
+#define REG_SHELL_ESCAPED NOTEST
+#endif
+#ifndef REG_SHELL_GROUP
+#define REG_SHELL_GROUP NOTEST
+#endif
+#ifndef REG_SHELL_PATH
+#define REG_SHELL_PATH NOTEST
+#endif
+#ifndef REG_SPAN
+#define REG_SPAN NOTEST
+#endif
+
+#define REG_UNKNOWN (-1)
+
+#ifndef REG_ENEWLINE
+#define REG_ENEWLINE (REG_UNKNOWN-1)
+#endif
+#ifndef REG_ENULL
+#ifndef REG_EMPTY
+#define REG_ENULL (REG_UNKNOWN-2)
+#else
+#define REG_ENULL REG_EMPTY
+#endif
+#endif
+#ifndef REG_ECOUNT
+#define REG_ECOUNT (REG_UNKNOWN-3)
+#endif
+#ifndef REG_BADESC
+#define REG_BADESC (REG_UNKNOWN-4)
+#endif
+#ifndef REG_EMEM
+#define REG_EMEM (REG_UNKNOWN-5)
+#endif
+#ifndef REG_EHUNG
+#define REG_EHUNG (REG_UNKNOWN-6)
+#endif
+#ifndef REG_EBUS
+#define REG_EBUS (REG_UNKNOWN-7)
+#endif
+#ifndef REG_EFAULT
+#define REG_EFAULT (REG_UNKNOWN-8)
+#endif
+#ifndef REG_EFLAGS
+#define REG_EFLAGS (REG_UNKNOWN-9)
+#endif
+#ifndef REG_EDELIM
+#define REG_EDELIM (REG_UNKNOWN-9)
+#endif
+
+static const struct { int code; char* name; } codes[] =
+{
+ REG_UNKNOWN, "UNKNOWN",
+ REG_NOMATCH, "NOMATCH",
+ REG_BADPAT, "BADPAT",
+ REG_ECOLLATE, "ECOLLATE",
+ REG_ECTYPE, "ECTYPE",
+ REG_EESCAPE, "EESCAPE",
+ REG_ESUBREG, "ESUBREG",
+ REG_EBRACK, "EBRACK",
+ REG_EPAREN, "EPAREN",
+ REG_EBRACE, "EBRACE",
+ REG_BADBR, "BADBR",
+ REG_ERANGE, "ERANGE",
+ REG_ESPACE, "ESPACE",
+ REG_BADRPT, "BADRPT",
+ REG_ENEWLINE, "ENEWLINE",
+ REG_ENULL, "ENULL",
+ REG_ECOUNT, "ECOUNT",
+ REG_BADESC, "BADESC",
+ REG_EMEM, "EMEM",
+ REG_EHUNG, "EHUNG",
+ REG_EBUS, "EBUS",
+ REG_EFAULT, "EFAULT",
+ REG_EFLAGS, "EFLAGS",
+ REG_EDELIM, "EDELIM",
+};
+
+static struct
+{
+ regmatch_t NOMATCH;
+ int errors;
+ int extracted;
+ int ignored;
+ int lineno;
+ int passed;
+ int signals;
+ int unspecified;
+ int verify;
+ int warnings;
+ char* file;
+ char* stack;
+ char* which;
+ jmp_buf gotcha;
+#ifdef REG_DISCIPLINE
+ Disc_t disc;
+#endif
+} state;
+
+static void
+quote(char* s, int len, unsigned long test)
+{
+ unsigned char* u = (unsigned char*)s;
+ unsigned char* e;
+ int c;
+#ifdef MB_CUR_MAX
+ int w;
+#endif
+
+ if (!u)
+ printf("NIL");
+ else if (!*u && len <= 1)
+ printf("NULL");
+ else if (test & TEST_EXPAND)
+ {
+ if (len < 0)
+ len = strlen((char*)u);
+ e = u + len;
+ if (test & TEST_DELIMIT)
+ printf("\"");
+ while (u < e)
+ switch (c = *u++)
+ {
+ case '\\':
+ printf("\\\\");
+ break;
+ case '"':
+ if (test & TEST_DELIMIT)
+ printf("\\\"");
+ else
+ printf("\"");
+ break;
+ case '\a':
+ printf("\\a");
+ break;
+ case '\b':
+ printf("\\b");
+ break;
+ case 033:
+ printf("\\e");
+ break;
+ case '\f':
+ printf("\\f");
+ break;
+ case '\n':
+ printf("\\n");
+ break;
+ case '\r':
+ printf("\\r");
+ break;
+ case '\t':
+ printf("\\t");
+ break;
+ case '\v':
+ printf("\\v");
+ break;
+ default:
+#ifdef MB_CUR_MAX
+ s = (char*)u - 1;
+ if ((w = mblen(s, (char*)e - s)) > 1)
+ {
+ u += w - 1;
+ fwrite(s, 1, w, stdout);
+ }
+ else
+#endif
+ if (!iscntrl(c) && isprint(c))
+ putchar(c);
+ else
+ printf("\\x%02x", c);
+ break;
+ }
+ if (test & TEST_DELIMIT)
+ printf("\"");
+ }
+ else
+ printf("%s", s);
+}
+
+static void
+report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
+{
+ if (state.file)
+ printf("%s:", state.file);
+ printf("%d:", state.lineno);
+ if (re)
+ {
+ printf(" ");
+ quote(re, -1, test|TEST_DELIMIT);
+ if (s)
+ {
+ printf(" versus ");
+ quote(s, len, test|TEST_DELIMIT);
+ }
+ }
+ if (test & TEST_UNSPECIFIED)
+ {
+ state.unspecified++;
+ printf(" unspecified behavior");
+ }
+ else
+ state.errors++;
+ if (state.which)
+ printf(" %s", state.which);
+ if (flags & REG_NOSUB)
+ printf(" NOSUB");
+ if (fun)
+ printf(" %s", fun);
+ if (comment[strlen(comment)-1] == '\n')
+ printf(" %s", comment);
+ else
+ {
+ printf(" %s: ", comment);
+ if (msg)
+ printf("%s: ", msg);
+ }
+}
+
+static void
+error(regex_t* preg, int code)
+{
+ char* msg;
+ char buf[256];
+
+ switch (code)
+ {
+ case REG_EBUS:
+ msg = "bus error";
+ break;
+ case REG_EFAULT:
+ msg = "memory fault";
+ break;
+ case REG_EHUNG:
+ msg = "did not terminate";
+ break;
+ default:
+ regerror(code, preg, msg = buf, sizeof buf);
+ break;
+ }
+ printf("%s\n", msg);
+}
+
+static void
+bad(char* comment, char* re, char* s, int len, unsigned long test)
+{
+ printf("bad test case ");
+ report(comment, NiL, re, s, len, NiL, 0, test);
+ exit(1);
+}
+
+static int
+escape(char* s)
+{
+ char* b;
+ char* t;
+ char* q;
+ char* e;
+ int c;
+
+ for (b = t = s; *t = *s; s++, t++)
+ if (*s == '\\')
+ switch (*++s)
+ {
+ case '\\':
+ break;
+ case 'a':
+ *t = '\a';
+ break;
+ case 'b':
+ *t = '\b';
+ break;
+ case 'c':
+ if (*t = *++s)
+ *t &= 037;
+ else
+ s--;
+ break;
+ case 'e':
+ case 'E':
+ *t = 033;
+ break;
+ case 'f':
+ *t = '\f';
+ break;
+ case 'n':
+ *t = '\n';
+ break;
+ case 'r':
+ *t = '\r';
+ break;
+ case 's':
+ *t = ' ';
+ break;
+ case 't':
+ *t = '\t';
+ break;
+ case 'v':
+ *t = '\v';
+ break;
+ case 'u':
+ case 'x':
+ c = 0;
+ q = c == 'u' ? (s + 5) : (char*)0;
+ e = s + 1;
+ while (!e || !q || s < q)
+ {
+ switch (*++s)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ c = (c << 4) + *s - 'a' + 10;
+ continue;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ c = (c << 4) + *s - 'A' + 10;
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ c = (c << 4) + *s - '0';
+ continue;
+ case '{':
+ case '[':
+ if (s != e)
+ {
+ s--;
+ break;
+ }
+ e = 0;
+ continue;
+ case '}':
+ case ']':
+ if (e)
+ s--;
+ break;
+ default:
+ s--;
+ break;
+ }
+ break;
+ }
+ *t = c;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = *s - '0';
+ q = s + 2;
+ while (s < q)
+ {
+ switch (*++s)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = (c << 3) + *s - '0';
+ break;
+ default:
+ q = --s;
+ break;
+ }
+ }
+ *t = c;
+ break;
+ default:
+ *(s + 1) = 0;
+ bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
+ }
+ return t - b;
+}
+
+static void
+matchoffprint(int off)
+{
+ switch (off)
+ {
+ case -2:
+ printf("X");
+ break;
+ case -1:
+ printf("?");
+ break;
+ default:
+ printf("%d", off);
+ break;
+ }
+}
+
+static void
+matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
+{
+ int i;
+
+ for (; nmatch > nsub + 1; nmatch--)
+ if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0))
+ break;
+ for (i = 0; i < nmatch; i++)
+ {
+ printf("(");
+ matchoffprint(match[i].rm_so);
+ printf(",");
+ matchoffprint(match[i].rm_eo);
+ printf(")");
+ }
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
+ {
+ if (ans)
+ printf(" expected: %s", ans);
+ printf("\n");
+ }
+}
+
+static int
+matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
+{
+ char* p;
+ int i;
+ int m;
+ int n;
+
+ if (streq(ans, "OK"))
+ return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
+ for (i = 0, p = ans; i < nmatch && *p; i++)
+ {
+ if (*p == '{')
+ {
+#ifdef REG_DISCIPLINE
+ char* x;
+
+ if (!(x = sfstruse(state.disc.sp)))
+ bad("out of space [discipline string]\n", NiL, NiL, 0, 0);
+ if (strcmp(p, x))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ return 0;
+ report("callout failed", NiL, re, s, len, NiL, flags, test);
+ quote(p, -1, test);
+ printf(" expected, ");
+ quote(x, -1, test);
+ printf(" returned\n");
+ }
+#endif
+ break;
+ }
+ if (*p++ != '(')
+ bad("improper answer\n", re, s, -1, test);
+ if (*p == '?')
+ {
+ m = -1;
+ p++;
+ }
+ else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
+ {
+ m = RE_DUP_MAX;
+ p += 10;
+ if (*p == '+' || *p == '-')
+ m += strtol(p, &p, 10);
+ }
+ else
+ m = strtol(p, &p, 10);
+ if (*p++ != ',')
+ bad("improper answer\n", re, s, -1, test);
+ if (*p == '?')
+ {
+ n = -1;
+ p++;
+ }
+ else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
+ {
+ n = RE_DUP_MAX;
+ p += 10;
+ if (*p == '+' || *p == '-')
+ n += strtol(p, &p, 10);
+ }
+ else
+ n = strtol(p, &p, 10);
+ if (*p++ != ')')
+ bad("improper answer\n", re, s, -1, test);
+ if (m!=match[i].rm_so || n!=match[i].rm_eo)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
+ {
+ report("failed: match was", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch, nsub, ans, test);
+ }
+ return 0;
+ }
+ }
+ for (; i < nmatch; i++)
+ {
+ if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
+ {
+ if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
+ {
+ state.ignored++;
+ return 0;
+ }
+ if (!(test & TEST_SUMMARY))
+ {
+ report("failed: match was", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch, nsub, ans, test);
+ }
+ }
+ return 0;
+ }
+ }
+ if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
+ {
+ report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch + 1, nsub, NiL, test);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static void
+sigunblock(int s)
+{
+#ifdef SIG_SETMASK
+ int op;
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ if (s)
+ {
+ sigaddset(&mask, s);
+ op = SIG_UNBLOCK;
+ }
+ else op = SIG_SETMASK;
+ sigprocmask(op, &mask, NiL);
+#else
+#ifdef sigmask
+ sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
+#endif
+#endif
+}
+
+static void
+gotcha(int sig)
+{
+ int ret;
+
+ signal(sig, gotcha);
+ alarm(0);
+ state.signals++;
+ switch (sig)
+ {
+ case SIGALRM:
+ ret = REG_EHUNG;
+ break;
+ case SIGBUS:
+ ret = REG_EBUS;
+ break;
+ default:
+ ret = REG_EFAULT;
+ break;
+ }
+ sigunblock(sig);
+ longjmp(state.gotcha, ret);
+}
+
+static char*
+get_line(FILE* fp)
+{
+ static char buf[32 * 1024];
+
+ register char* s = buf;
+ register char* e = &buf[sizeof(buf)];
+ register char* b;
+
+ for (;;)
+ {
+ if (!(b = fgets(s, e - s, fp)))
+ return 0;
+ state.lineno++;
+ s += strlen(s);
+ if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
+ {
+ *s = 0;
+ break;
+ }
+ s--;
+ }
+ return buf;
+}
+
+static unsigned long
+note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
+{
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
+ {
+ printf("NOTE\t");
+ if (msg)
+ printf("%s: ", msg);
+ printf("skipping lines %d", state.lineno);
+ }
+ return skip | level;
+}
+
+#define TABS(n) &ts[7-((n)&7)]
+
+static char ts[] = "\t\t\t\t\t\t\t";
+
+static unsigned long
+extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
+{
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
+ {
+ state.extracted = 1;
+ if (test & TEST_OK)
+ {
+ state.passed++;
+ if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ if (msg && strcmp(msg, "EXPECTED"))
+ printf("NOTE\t%s\n", msg);
+ return skip;
+ }
+ test &= ~(TEST_PASS|TEST_QUERY);
+ }
+ if (test & (TEST_QUERY|TEST_VERIFY))
+ {
+ if (test & TEST_BASELINE)
+ test &= ~(TEST_BASELINE|TEST_PASS);
+ else
+ test |= TEST_PASS;
+ skip |= level;
+ }
+ if (!(test & TEST_OK))
+ {
+ if (test & TEST_UNSPECIFIED)
+ state.unspecified++;
+ else
+ state.errors++;
+ }
+ if (test & (TEST_PASS|TEST_SUMMARY))
+ return skip;
+ test &= ~TEST_DELIMIT;
+ printf("%s%s", spec, TABS(*tabs++));
+ if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
+ printf("SAME");
+ else
+ quote(re, -1, test);
+ printf("%s", TABS(*tabs++));
+ quote(s, -1, test);
+ printf("%s", TABS(*tabs++));
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || !accept && !match)
+ printf("%s", ans);
+ else if (accept)
+ printf("%s", accept);
+ else
+ matchprint(match, nmatch, nsub, NiL, test);
+ if (msg)
+ printf("%s%s", TABS(*tabs++), msg);
+ putchar('\n');
+ }
+ else if (test & TEST_QUERY)
+ skip = note(level, msg, skip, test);
+ else if (test & TEST_VERIFY)
+ state.extracted = 1;
+ return skip;
+}
+
+static int
+catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
+{
+ int eret;
+
+ if (!(test & TEST_CATCH))
+ {
+ regfree(preg);
+ eret = 0;
+ }
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ regfree(preg);
+ alarm(0);
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ else
+ {
+ report("failed", "regfree", re, NiL, -1, msg, flags, test);
+ error(preg, eret);
+ }
+ return eret;
+}
+
+static char*
+expand(char* os, char* ot)
+{
+ char* s = os;
+ char* t;
+ int n = 0;
+ int r;
+ long m;
+
+ for (;;)
+ {
+ switch (*s++)
+ {
+ case 0:
+ break;
+ case '{':
+ n++;
+ continue;
+ case '}':
+ n--;
+ continue;
+ case 'R':
+ if (n == 1 && !memcmp(s, "E_DUP_MAX", 9))
+ {
+ s--;
+ for (t = ot; os < s; *t++ = *os++);
+ r = ((t - ot) >= 5 && t[-1] == '{' && t[-2] == '.' && t[-3] == '.' && t[-4] == '.') ? t[-5] : 0;
+ os = ot;
+ m = RE_DUP_MAX;
+ if (*(s += 10) == '+' || *s == '-')
+ m += strtol(s, &s, 10);
+ if (r)
+ {
+ t -= 5;
+ while (m-- > 0)
+ *t++ = r;
+ while (*s && *s++ != '}');
+ }
+ else
+ t += snprintf(t, 32, "%ld", m);
+ while (*t = *s++)
+ t++;
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ return os;
+}
+
+int
+main(int argc, char** argv)
+{
+ int flags;
+ int cflags;
+ int eflags;
+ int nmatch;
+ int nexec;
+ int nstr;
+ int cret;
+ int eret;
+ int nsub;
+ int i;
+ int j;
+ int expected;
+ int got;
+ int locale;
+ int subunitlen;
+ int testno;
+ unsigned long level;
+ unsigned long skip;
+ char* p;
+ char* line;
+ char* spec;
+ char* re;
+ char* s;
+ char* ans;
+ char* msg;
+ char* fun;
+ char* ppat;
+ char* subunit;
+ char* version;
+ char* field[6];
+ char* delim[6];
+ FILE* fp;
+ int tabs[6];
+ char unit[64];
+ regmatch_t match[100];
+ regex_t preg;
+
+ static char pat[32 * 1024];
+ static char patbuf[32 * 1024];
+ static char strbuf[32 * 1024];
+
+ int nonosub = REG_NOSUB == 0;
+ int nonexec = 0;
+
+ unsigned long test = 0;
+
+ static char* filter[] = { "-", 0 };
+
+ state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
+ p = unit;
+ version = (char*)id + 10;
+ while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
+ p++;
+ *p = 0;
+ while ((p = *++argv) && *p == '-')
+ for (;;)
+ {
+ switch (*++p)
+ {
+ case 0:
+ break;
+ case 'c':
+ test |= TEST_CATCH;
+ continue;
+ case 'e':
+ test |= TEST_IGNORE_ERROR;
+ continue;
+ case 'h':
+ case '?':
+ help(0);
+ return 2;
+ case '-':
+ help(p[1] == 'h');
+ return 2;
+ case 'n':
+ nonexec = 1;
+ continue;
+ case 'o':
+ test |= TEST_IGNORE_OVER;
+ continue;
+ case 'p':
+ test |= TEST_IGNORE_POSITION;
+ continue;
+ case 's':
+#ifdef REG_DISCIPLINE
+ if (!(state.stack = stkalloc(stkstd, 0)))
+ fprintf(stderr, "%s: out of space [stack]", unit);
+ state.disc.disc.re_resizef = resizef;
+ state.disc.disc.re_resizehandle = (void*)stkstd;
+#endif
+ continue;
+ case 'x':
+ nonosub = 1;
+ continue;
+ case 'v':
+ test |= TEST_VERBOSE;
+ continue;
+ case 'A':
+ test |= TEST_ACTUAL;
+ continue;
+ case 'B':
+ test |= TEST_BASELINE;
+ continue;
+ case 'F':
+ test |= TEST_FAIL;
+ continue;
+ case 'P':
+ test |= TEST_PASS;
+ continue;
+ case 'S':
+ test |= TEST_SUMMARY;
+ continue;
+ default:
+ fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
+ return 2;
+ }
+ break;
+ }
+ if (!*argv)
+ argv = filter;
+ locale = 0;
+ while (state.file = *argv++)
+ {
+ if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
+ {
+ state.file = 0;
+ fp = stdin;
+ }
+ else if (!(fp = fopen(state.file, "r")))
+ {
+ fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
+ return 2;
+ }
+ testno = state.errors = state.ignored = state.lineno = state.passed =
+ state.signals = state.unspecified = state.warnings = 0;
+ skip = 0;
+ level = 1;
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ printf("TEST\t%s ", unit);
+ if (s = state.file)
+ {
+ subunit = p = 0;
+ for (;;)
+ {
+ switch (*s++)
+ {
+ case 0:
+ break;
+ case '/':
+ subunit = s;
+ continue;
+ case '.':
+ p = s - 1;
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (!subunit)
+ subunit = state.file;
+ if (p < subunit)
+ p = s - 1;
+ subunitlen = p - subunit;
+ printf("%-.*s ", subunitlen, subunit);
+ }
+ else
+ subunit = 0;
+ for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
+ putchar(*s);
+ if (test & TEST_CATCH)
+ printf(", catch");
+ if (test & TEST_IGNORE_ERROR)
+ printf(", ignore error code mismatches");
+ if (test & TEST_IGNORE_POSITION)
+ printf(", ignore negative position mismatches");
+#ifdef REG_DISCIPLINE
+ if (state.stack)
+ printf(", stack");
+#endif
+ if (test & TEST_VERBOSE)
+ printf(", verbose");
+ printf("\n");
+#ifdef REG_VERSIONID
+ if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
+ s = pat;
+ else
+#endif
+#ifdef REG_TEST_VERSION
+ s = REG_TEST_VERSION;
+#else
+ s = "regex";
+#endif
+ printf("NOTE\t%s\n", s);
+ if (elementsof(unsupported) > 1)
+ {
+#if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
+ i = 0;
+#else
+ i = REG_EXTENDED != 0;
+#endif
+ for (got = 0; i < elementsof(unsupported) - 1; i++)
+ {
+ if (!got)
+ {
+ got = 1;
+ printf("NOTE\tunsupported: %s", unsupported[i]);
+ }
+ else
+ printf(",%s", unsupported[i]);
+ }
+ if (got)
+ printf("\n");
+ }
+ }
+#ifdef REG_DISCIPLINE
+ state.disc.disc.re_version = REG_VERSION;
+ state.disc.disc.re_compf = compf;
+ state.disc.disc.re_execf = execf;
+ if (!(state.disc.sp = sfstropen()))
+ bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
+ preg.re_disc = &state.disc.disc;
+#endif
+ if (test & TEST_CATCH)
+ {
+ signal(SIGALRM, gotcha);
+ signal(SIGBUS, gotcha);
+ signal(SIGSEGV, gotcha);
+ }
+ while (p = get_line(fp))
+ {
+
+ /* parse: */
+
+ line = p;
+ if (*p == ':' && !isspace(*(p + 1)))
+ {
+ while (*++p && *p != ':');
+ if (!*p++)
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ continue;
+ }
+ }
+ while (isspace(*p))
+ p++;
+ if (*p == 0 || *p == '#' || *p == 'T')
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ continue;
+ }
+ if (*p == ':' || *p == 'N')
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ while (*++p && !isspace(*p));
+ while (isspace(*p))
+ p++;
+ printf("NOTE %s\n", p);
+ }
+ continue;
+ }
+ j = 0;
+ i = 0;
+ field[i++] = p;
+ for (;;)
+ {
+ switch (*p++)
+ {
+ case 0:
+ p--;
+ j = 0;
+ goto checkfield;
+ case '\t':
+ *(delim[i] = p - 1) = 0;
+ j = 1;
+ checkfield:
+ s = field[i - 1];
+ if (streq(s, "NIL"))
+ field[i - 1] = 0;
+ else if (streq(s, "NULL"))
+ *s = 0;
+ while (*p == '\t')
+ {
+ p++;
+ j++;
+ }
+ tabs[i - 1] = j;
+ if (!*p)
+ break;
+ if (i >= elementsof(field))
+ bad("too many fields\n", NiL, NiL, 0, 0);
+ field[i++] = p;
+ /*FALLTHROUGH*/
+ default:
+ continue;
+ }
+ break;
+ }
+ if (!(spec = field[0]))
+ bad("NIL spec\n", NiL, NiL, 0, 0);
+
+ /* interpret: */
+
+ cflags = REG_TEST_DEFAULT;
+ eflags = REG_EXEC_DEFAULT;
+ test &= TEST_GLOBAL;
+ state.extracted = 0;
+ nmatch = 20;
+ nsub = -1;
+ for (p = spec; *p; p++)
+ {
+ if (isdigit(*p))
+ {
+ nmatch = strtol(p, &p, 10);
+ if (nmatch >= elementsof(match))
+ bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
+ p--;
+ continue;
+ }
+ switch (*p)
+ {
+ case 'A':
+ test |= TEST_ARE;
+ continue;
+ case 'B':
+ test |= TEST_BRE;
+ continue;
+ case 'C':
+ if (!(test & TEST_QUERY) && !(skip & level))
+ bad("locale must be nested\n", NiL, NiL, 0, 0);
+ test &= ~TEST_QUERY;
+ if (locale)
+ bad("locale nesting not supported\n", NiL, NiL, 0, 0);
+ if (i != 2)
+ bad("locale field expected\n", NiL, NiL, 0, 0);
+ if (!(skip & level))
+ {
+#if defined(LC_COLLATE) && defined(LC_CTYPE)
+ s = field[1];
+ if (!s || streq(s, "POSIX"))
+ s = "C";
+ if ((ans = setlocale(LC_COLLATE, s)) && streq(ans, "POSIX"))
+ ans = "C";
+ if (!ans || !streq(ans, s) && streq(s, "C"))
+ ans = 0;
+ else if ((ans = setlocale(LC_CTYPE, s)) && streq(ans, "POSIX"))
+ ans = "C";
+ if (!ans || !streq(ans, s) && streq(s, "C"))
+ skip = note(level, s, skip, test);
+ else
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ printf("NOTE \"%s\" locale\n", s);
+ locale = level;
+ }
+#else
+ skip = note(level, skip, test, "locales not supported");
+#endif
+ }
+ cflags = NOTEST;
+ continue;
+ case 'E':
+ test |= TEST_ERE;
+ continue;
+ case 'K':
+ test |= TEST_KRE;
+ continue;
+ case 'L':
+ test |= TEST_LRE;
+ continue;
+ case 'S':
+ test |= TEST_SRE;
+ continue;
+
+ case 'a':
+ cflags |= REG_LEFT|REG_RIGHT;
+ continue;
+ case 'b':
+ eflags |= REG_NOTBOL;
+ continue;
+ case 'c':
+ cflags |= REG_COMMENT;
+ continue;
+ case 'd':
+ cflags |= REG_SHELL_DOT;
+ continue;
+ case 'e':
+ eflags |= REG_NOTEOL;
+ continue;
+ case 'f':
+ cflags |= REG_MULTIPLE;
+ continue;
+ case 'g':
+ cflags |= NOTEST;
+ continue;
+ case 'h':
+ cflags |= REG_MULTIREF;
+ continue;
+ case 'i':
+ cflags |= REG_ICASE;
+ continue;
+ case 'j':
+ cflags |= REG_SPAN;
+ continue;
+ case 'k':
+ cflags |= REG_ESCAPE;
+ continue;
+ case 'l':
+ cflags |= REG_LEFT;
+ continue;
+ case 'm':
+ cflags |= REG_MINIMAL;
+ continue;
+ case 'n':
+ cflags |= REG_NEWLINE;
+ continue;
+ case 'o':
+ cflags |= REG_SHELL_GROUP;
+ continue;
+ case 'p':
+ cflags |= REG_SHELL_PATH;
+ continue;
+ case 'q':
+ cflags |= REG_DELIMITED;
+ continue;
+ case 'r':
+ cflags |= REG_RIGHT;
+ continue;
+ case 's':
+ cflags |= REG_SHELL_ESCAPED;
+ continue;
+ case 't':
+ cflags |= REG_MUSTDELIM;
+ continue;
+ case 'u':
+ test |= TEST_UNSPECIFIED;
+ continue;
+ case 'v':
+ cflags |= REG_CLASS_ESCAPE;
+ continue;
+ case 'w':
+ cflags |= REG_NOSUB;
+ continue;
+ case 'x':
+ if (REG_LENIENT)
+ cflags |= REG_LENIENT;
+ else
+ test |= TEST_LENIENT;
+ continue;
+ case 'y':
+ eflags |= REG_LEFT;
+ continue;
+ case 'z':
+ cflags |= REG_NULL;
+ continue;
+
+ case '$':
+ test |= TEST_EXPAND;
+ continue;
+
+ case '/':
+ test |= TEST_SUB;
+ continue;
+
+ case '=':
+ test |= TEST_DECOMP;
+ continue;
+
+ case '?':
+ test |= TEST_VERIFY;
+ test &= ~(TEST_AND|TEST_OR);
+ state.verify = state.passed;
+ continue;
+ case '&':
+ test |= TEST_VERIFY|TEST_AND;
+ test &= ~TEST_OR;
+ continue;
+ case '|':
+ test |= TEST_VERIFY|TEST_OR;
+ test &= ~TEST_AND;
+ continue;
+ case ';':
+ test |= TEST_OR;
+ test &= ~TEST_AND;
+ continue;
+
+ case '{':
+ level <<= 1;
+ if (skip & (level >> 1))
+ {
+ skip |= level;
+ cflags = NOTEST;
+ }
+ else
+ {
+ skip &= ~level;
+ test |= TEST_QUERY;
+ }
+ continue;
+ case '}':
+ if (level == 1)
+ bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
+ if ((skip & level) && !(skip & (level>>1)))
+ {
+ if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
+ {
+ if (test & (TEST_ACTUAL|TEST_FAIL))
+ printf("}\n");
+ else if (!(test & TEST_PASS))
+ printf("-%d\n", state.lineno);
+ }
+ }
+#if defined(LC_COLLATE) && defined(LC_CTYPE)
+ else if (locale & level)
+ {
+ locale = 0;
+ if (!(skip & level))
+ {
+ s = "C";
+ setlocale(LC_COLLATE, s);
+ setlocale(LC_CTYPE, s);
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ printf("NOTE \"%s\" locale\n", s);
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
+ printf("}\n");
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
+ printf("}\n");
+ }
+#endif
+ level >>= 1;
+ cflags = NOTEST;
+ continue;
+
+ default:
+ bad("bad spec\n", spec, NiL, 0, test);
+ break;
+
+ }
+ break;
+ }
+ if ((cflags|eflags) == NOTEST || (skip & level) && (test & TEST_BASELINE))
+ {
+ if (test & TEST_BASELINE)
+ {
+ while (i > 1)
+ *delim[--i] = '\t';
+ printf("%s\n", line);
+ }
+ continue;
+ }
+ if (test & TEST_OR)
+ {
+ if (!(test & TEST_VERIFY))
+ {
+ test &= ~TEST_OR;
+ if (state.passed == state.verify && i > 1)
+ printf("NOTE\t%s\n", field[1]);
+ continue;
+ }
+ else if (state.passed > state.verify)
+ continue;
+ }
+ else if (test & TEST_AND)
+ {
+ if (state.passed == state.verify)
+ continue;
+ state.passed = state.verify;
+ }
+ if (i < ((test & TEST_DECOMP) ? 3 : 4))
+ bad("too few fields\n", NiL, NiL, 0, test);
+ while (i < elementsof(field))
+ field[i++] = 0;
+ if (re = field[1])
+ {
+ if (streq(re, "SAME"))
+ {
+ re = ppat;
+ test |= TEST_SAME;
+ }
+ else
+ {
+ if (test & TEST_EXPAND)
+ escape(re);
+ re = expand(re, patbuf);
+ strcpy(ppat = pat, re);
+ }
+ }
+ else
+ ppat = 0;
+ nstr = -1;
+ if (s = field[2])
+ {
+ s = expand(s, strbuf);
+ if (test & TEST_EXPAND)
+ {
+ nstr = escape(s);
+#if _REG_nexec
+ if (nstr != strlen(s))
+ nexec = nstr;
+#endif
+ }
+ }
+ if (!(ans = field[(test & TEST_DECOMP) ? 2 : 3]))
+ bad("NIL answer\n", NiL, NiL, 0, test);
+ msg = field[4];
+ fflush(stdout);
+ if (test & TEST_SUB)
+#if _REG_subcomp
+ cflags |= REG_DELIMITED;
+#else
+ continue;
+#endif
+#if !_REG_decomp
+ if (test & TEST_DECOMP)
+ continue;
+#endif
+
+ compile:
+
+ if (state.extracted || (skip & level))
+ continue;
+#if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
+#ifdef REG_EXTENDED
+ if (REG_EXTENDED != 0 && (test & TEST_BRE))
+#else
+ if (test & TEST_BRE)
+#endif
+ {
+ test &= ~TEST_BRE;
+ flags = cflags;
+ state.which = "BRE";
+ }
+ else
+#endif
+#ifdef REG_EXTENDED
+ if (test & TEST_ERE)
+ {
+ test &= ~TEST_ERE;
+ flags = cflags | REG_EXTENDED;
+ state.which = "ERE";
+ }
+ else
+#endif
+#ifdef REG_AUGMENTED
+ if (test & TEST_ARE)
+ {
+ test &= ~TEST_ARE;
+ flags = cflags | REG_AUGMENTED;
+ state.which = "ARE";
+ }
+ else
+#endif
+#ifdef REG_LITERAL
+ if (test & TEST_LRE)
+ {
+ test &= ~TEST_LRE;
+ flags = cflags | REG_LITERAL;
+ state.which = "LRE";
+ }
+ else
+#endif
+#ifdef REG_SHELL
+ if (test & TEST_SRE)
+ {
+ test &= ~TEST_SRE;
+ flags = cflags | REG_SHELL;
+ state.which = "SRE";
+ }
+ else
+#ifdef REG_AUGMENTED
+ if (test & TEST_KRE)
+ {
+ test &= ~TEST_KRE;
+ flags = cflags | REG_SHELL | REG_AUGMENTED;
+ state.which = "KRE";
+ }
+ else
+#endif
+#endif
+ {
+ if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
+ extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
+ continue;
+ }
+ if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
+ {
+ printf("test %-3d %s ", state.lineno, state.which);
+ quote(re, -1, test|TEST_DELIMIT);
+ printf(" ");
+ quote(s, nstr, test|TEST_DELIMIT);
+ printf("\n");
+ }
+
+ nosub:
+ fun = "regcomp";
+#if _REG_nexec
+ if (nstr >= 0 && nstr != strlen(s))
+ nexec = nstr;
+
+ else
+#endif
+ nexec = -1;
+ if (state.extracted || (skip & level))
+ continue;
+ if (!(test & TEST_QUERY))
+ testno++;
+#ifdef REG_DISCIPLINE
+ if (state.stack)
+ stkset(stkstd, state.stack, 0);
+ flags |= REG_DISCIPLINE;
+ state.disc.ordinal = 0;
+ sfstrseek(state.disc.sp, 0, SEEK_SET);
+#endif
+ if (!(test & TEST_CATCH))
+ cret = regcomp(&preg, re, flags);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ cret = regcomp(&preg, re, flags);
+ alarm(0);
+ }
+#if _REG_subcomp
+ if (!cret && (test & TEST_SUB))
+ {
+ fun = "regsubcomp";
+ p = re + preg.re_npat;
+ if (!(test & TEST_CATCH))
+ cret = regsubcomp(&preg, p, NiL, 0, 0);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ cret = regsubcomp(&preg, p, NiL, 0, 0);
+ alarm(0);
+ }
+ if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
+ {
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ cret = REG_EFLAGS;
+ }
+ }
+#endif
+#if _REG_decomp
+ if (!cret && (test & TEST_DECOMP))
+ {
+ char buf[128];
+
+ if ((j = nmatch) > sizeof(buf))
+ j = sizeof(buf);
+ fun = "regdecomp";
+ p = re + preg.re_npat;
+ if (!(test & TEST_CATCH))
+ i = regdecomp(&preg, -1, buf, j);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ i = regdecomp(&preg, -1, buf, j);
+ alarm(0);
+ }
+ if (!cret)
+ {
+ catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ if (i > j)
+ {
+ if (i != (strlen(ans) + 1))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ printf(" %d byte buffer supplied, %d byte buffer required\n", j, i);
+ }
+ }
+ else if (strcmp(buf, ans))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ quote(ans, -1, test|TEST_DELIMIT);
+ printf(" expected, ");
+ quote(buf, -1, test|TEST_DELIMIT);
+ printf(" returned\n");
+ }
+ continue;
+ }
+ }
+#endif
+ if (!cret)
+ {
+ if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
+ {
+ for (p = ans; *p; p++)
+ if (*p == '(')
+ nsub++;
+ else if (*p == '{')
+ nsub--;
+ if (nsub >= 0)
+ {
+ if (test & TEST_IGNORE_OVER)
+ {
+ if (nmatch > nsub)
+ nmatch = nsub + 1;
+ }
+ else if (nsub != preg.re_nsub)
+ {
+ if (nsub > preg.re_nsub)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
+ printf("at least %d expected, %d returned\n", nsub, preg.re_nsub);
+ state.errors++;
+ }
+ }
+ else
+ nsub = preg.re_nsub;
+ }
+ }
+ }
+ if (!(test & (TEST_DECOMP|TEST_SUB)) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else if (!(test & TEST_LENIENT))
+ {
+ report("failed", fun, re, NiL, -1, msg, flags, test);
+ printf("%s expected, OK returned\n", ans);
+ }
+ catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ continue;
+ }
+ }
+ else
+ {
+ if (test & TEST_LENIENT)
+ /* we'll let it go this time */;
+ else if (!*ans || ans[0]=='(' || cret == REG_BADPAT && streq(ans, "NOMATCH"))
+ {
+ got = 0;
+ for (i = 1; i < elementsof(codes); i++)
+ if (cret==codes[i].code)
+ got = i;
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed", fun, re, NiL, -1, msg, flags, test);
+ printf("%s returned: ", codes[got].name);
+ error(&preg, cret);
+ }
+ }
+ else
+ {
+ expected = got = 0;
+ for (i = 1; i < elementsof(codes); i++)
+ {
+ if (streq(ans, codes[i].name))
+ expected = i;
+ if (cret==codes[i].code)
+ got = i;
+ }
+ if (!expected)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
+ printf("%s expected, %s returned\n", ans, codes[got].name);
+ }
+ }
+ else if (cret != codes[expected].code && cret != REG_BADPAT)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else if (test & TEST_IGNORE_ERROR)
+ state.ignored++;
+ else
+ {
+ report("should fail and did", fun, re, NiL, -1, msg, flags, test);
+ printf("%s expected, %s returned: ", ans, codes[got].name);
+ state.errors--;
+ state.warnings++;
+ error(&preg, cret);
+ }
+ }
+ }
+ goto compile;
+ }
+
+#if _REG_nexec
+ execute:
+ if (nexec >= 0)
+ fun = "regnexec";
+ else
+#endif
+ fun = "regexec";
+
+ for (i = 0; i < elementsof(match); i++)
+ match[i] = state.NOMATCH;
+
+#if _REG_nexec
+ if (nexec >= 0)
+ {
+ eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
+ s[nexec] = 0;
+ }
+ else
+#endif
+ {
+ if (!(test & TEST_CATCH))
+ eret = regexec(&preg, s, nmatch, match, eflags);
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ eret = regexec(&preg, s, nmatch, match, eflags);
+ alarm(0);
+ }
+ }
+#if _REG_subcomp
+ if ((test & TEST_SUB) && !eret)
+ {
+ fun = "regsubexec";
+ if (!(test & TEST_CATCH))
+ eret = regsubexec(&preg, s, nmatch, match);
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ eret = regsubexec(&preg, s, nmatch, match);
+ alarm(0);
+ }
+ }
+#endif
+ if (flags & REG_NOSUB)
+ {
+ if (eret)
+ {
+ if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
+ error(&preg, eret);
+ }
+ }
+ }
+ else if (streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
+ error(&preg, eret);
+ }
+ }
+ }
+ else if (eret)
+ {
+ if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ if (eret != REG_NOMATCH)
+ error(&preg, eret);
+ else if (*ans)
+ printf("expected: %s\n", ans);
+ else
+ printf("\n");
+ }
+ }
+ }
+ else if (streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
+ matchprint(match, nmatch, nsub, NiL, test);
+ }
+ }
+#if _REG_subcomp
+ else if (test & TEST_SUB)
+ {
+ p = preg.re_sub->re_buf;
+ if (strcmp(p, ans))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ quote(ans, -1, test|TEST_DELIMIT);
+ printf(" expected, ");
+ quote(p, -1, test|TEST_DELIMIT);
+ printf(" returned\n");
+ }
+ }
+#endif
+ else if (!*ans)
+ {
+ if (match[0].rm_so != state.NOMATCH.rm_so)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ else
+ {
+ report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
+ matchprint(match, nmatch, nsub, NiL, test);
+ }
+ }
+ }
+ else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
+ {
+#if _REG_nexec
+ if (nexec < 0 && !nonexec)
+ {
+ nexec = nstr >= 0 ? nstr : strlen(s);
+ s[nexec] = '\n';
+ testno++;
+ goto execute;
+ }
+#endif
+ if (!(test & (TEST_DECOMP|TEST_SUB|TEST_VERIFY)) && !nonosub)
+ {
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ flags |= REG_NOSUB;
+ goto nosub;
+ }
+ if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ goto compile;
+ }
+ if (test & TEST_SUMMARY)
+ printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
+ else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
+ {
+ printf("TEST\t%s", unit);
+ if (subunit)
+ printf(" %-.*s", subunitlen, subunit);
+ printf(", %d test%s", testno, testno == 1 ? "" : "s");
+ if (state.ignored)
+ printf(", %d ignored mismatche%s", state.ignored, state.ignored == 1 ? "" : "s");
+ if (state.warnings)
+ printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
+ if (state.unspecified)
+ printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
+ if (state.signals)
+ printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
+ printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
+ }
+ if (fp != stdin)
+ fclose(fp);
+ }
+ return 0;
+}