summaryrefslogtreecommitdiff
path: root/libc/posix
diff options
context:
space:
mode:
Diffstat (limited to 'libc/posix')
-rw-r--r--libc/posix/.cvsignore6
-rw-r--r--libc/posix/BOOST.tests829
-rw-r--r--libc/posix/Depend1
-rw-r--r--libc/posix/Makefile293
-rw-r--r--libc/posix/PCRE.tests2386
-rw-r--r--libc/posix/PTESTS341
-rw-r--r--libc/posix/PTESTS2C.sed6
-rw-r--r--libc/posix/TESTS167
-rw-r--r--libc/posix/TESTS2C.sed2
-rw-r--r--libc/posix/Versions128
-rw-r--r--libc/posix/_exit.c36
-rw-r--r--libc/posix/alarm.c39
-rw-r--r--libc/posix/annexc.c890
-rw-r--r--libc/posix/bits/posix1_lim.h168
-rw-r--r--libc/posix/bits/posix2_lim.h91
-rw-r--r--libc/posix/bits/unistd.h250
-rw-r--r--libc/posix/bsd-getpgrp.c32
-rw-r--r--libc/posix/bug-ga1.c23
-rw-r--r--libc/posix/bug-ga2.c30
-rw-r--r--libc/posix/bug-glob1.c88
-rw-r--r--libc/posix/bug-glob2.c303
-rw-r--r--libc/posix/bug-regex1.c65
-rw-r--r--libc/posix/bug-regex10.c61
-rw-r--r--libc/posix/bug-regex11.c139
-rw-r--r--libc/posix/bug-regex12.c73
-rw-r--r--libc/posix/bug-regex13.c103
-rw-r--r--libc/posix/bug-regex14.c54
-rw-r--r--libc/posix/bug-regex15.c32
-rw-r--r--libc/posix/bug-regex16.c35
-rw-r--r--libc/posix/bug-regex17.c95
-rw-r--r--libc/posix/bug-regex18.c100
-rw-r--r--libc/posix/bug-regex19.c418
-rw-r--r--libc/posix/bug-regex2.c54
-rw-r--r--libc/posix/bug-regex20.c287
-rw-r--r--libc/posix/bug-regex21.c45
-rw-r--r--libc/posix/bug-regex22.c119
-rw-r--r--libc/posix/bug-regex23.c35
-rw-r--r--libc/posix/bug-regex24.c60
-rw-r--r--libc/posix/bug-regex25.c57
-rw-r--r--libc/posix/bug-regex3.c45
-rw-r--r--libc/posix/bug-regex4.c60
-rw-r--r--libc/posix/bug-regex5.c62
-rw-r--r--libc/posix/bug-regex6.c76
-rw-r--r--libc/posix/bug-regex7.c92
-rw-r--r--libc/posix/bug-regex8.c84
-rw-r--r--libc/posix/bug-regex9.c67
-rw-r--r--libc/posix/confstr.c280
-rw-r--r--libc/posix/cpio.h74
-rw-r--r--libc/posix/environ.c12
-rw-r--r--libc/posix/execl.c73
-rw-r--r--libc/posix/execle.c73
-rw-r--r--libc/posix/execlp.c73
-rw-r--r--libc/posix/execv.c27
-rw-r--r--libc/posix/execve.c44
-rw-r--r--libc/posix/execvp.c198
-rw-r--r--libc/posix/fexecve.c43
-rw-r--r--libc/posix/fnmatch.c418
-rw-r--r--libc/posix/fnmatch.h72
-rw-r--r--libc/posix/fnmatch_loop.c1207
-rw-r--r--libc/posix/fork.c36
-rw-r--r--libc/posix/fpathconf.c62
-rw-r--r--libc/posix/gai.conf52
-rw-r--r--libc/posix/gai_strerror.c29
-rw-r--r--libc/posix/get_child_max.c29
-rw-r--r--libc/posix/getaddrinfo.c41
-rw-r--r--libc/posix/getconf.c1171
-rw-r--r--libc/posix/getegid.c32
-rw-r--r--libc/posix/geteuid.c33
-rw-r--r--libc/posix/getgid.c33
-rw-r--r--libc/posix/getgroups.c48
-rw-r--r--libc/posix/getlogin.c33
-rw-r--r--libc/posix/getlogin_r.c37
-rw-r--r--libc/posix/getopt.c1225
-rw-r--r--libc/posix/getopt.h177
-rw-r--r--libc/posix/getopt1.c192
-rw-r--r--libc/posix/getopt_init.c75
-rw-r--r--libc/posix/getopt_int.h130
-rw-r--r--libc/posix/getpgid.c33
-rw-r--r--libc/posix/getpgrp.c27
-rw-r--r--libc/posix/getpid.c34
-rw-r--r--libc/posix/getppid.c33
-rw-r--r--libc/posix/getresgid.c35
-rw-r--r--libc/posix/getresuid.c35
-rw-r--r--libc/posix/getsid.c32
-rw-r--r--libc/posix/getuid.c33
-rw-r--r--libc/posix/glob.c1303
-rw-r--r--libc/posix/glob.h194
-rw-r--r--libc/posix/glob/ChangeLog23
-rw-r--r--libc/posix/glob/Makefile.ami69
-rw-r--r--libc/posix/glob/Makefile.in66
-rw-r--r--libc/posix/glob/SCOPTIONS13
-rw-r--r--libc/posix/glob/SMakefile68
-rwxr-xr-xlibc/posix/glob/configure1664
-rw-r--r--libc/posix/glob/configure.bat26
-rw-r--r--libc/posix/glob/configure.in19
-rw-r--r--libc/posix/glob64.c54
-rw-r--r--libc/posix/globtest.c119
-rwxr-xr-xlibc/posix/globtest.sh724
-rw-r--r--libc/posix/group_member.c50
-rw-r--r--libc/posix/init-posix.c1
-rw-r--r--libc/posix/nanosleep.c36
-rw-r--r--libc/posix/pathconf.c41
-rw-r--r--libc/posix/pause.c34
-rw-r--r--libc/posix/posix_madvise.c32
-rw-r--r--libc/posix/pread.c46
-rw-r--r--libc/posix/pread64.c46
-rw-r--r--libc/posix/ptestcases.h326
-rw-r--r--libc/posix/pwrite.c46
-rw-r--r--libc/posix/pwrite64.c47
-rw-r--r--libc/posix/re_comp.h26
-rw-r--r--libc/posix/regcomp.c3800
-rw-r--r--libc/posix/regex.c74
-rw-r--r--libc/posix/regex.h556
-rw-r--r--libc/posix/regex_internal.c1651
-rw-r--r--libc/posix/regex_internal.h763
-rw-r--r--libc/posix/regexbug1.c51
-rw-r--r--libc/posix/regexec.c4329
-rw-r--r--libc/posix/runptests.c123
-rw-r--r--libc/posix/runtests.c138
-rw-r--r--libc/posix/rxspencer/COPYRIGHT20
-rw-r--r--libc/posix/rxspencer/tests538
-rw-r--r--libc/posix/sched.h86
-rw-r--r--libc/posix/sched_getaffinity.c35
-rw-r--r--libc/posix/sched_getp.c34
-rw-r--r--libc/posix/sched_gets.c34
-rw-r--r--libc/posix/sched_primax.c33
-rw-r--r--libc/posix/sched_primin.c33
-rw-r--r--libc/posix/sched_rr_gi.c34
-rw-r--r--libc/posix/sched_setaffinity.c35
-rw-r--r--libc/posix/sched_setp.c34
-rw-r--r--libc/posix/sched_sets.c35
-rw-r--r--libc/posix/sched_yield.c34
-rw-r--r--libc/posix/setgid.c37
-rw-r--r--libc/posix/setlogin.c32
-rw-r--r--libc/posix/setpgid.c37
-rw-r--r--libc/posix/setpgrp.c25
-rw-r--r--libc/posix/setresgid.c35
-rw-r--r--libc/posix/setresuid.c35
-rw-r--r--libc/posix/setsid.c35
-rw-r--r--libc/posix/setuid.c37
-rw-r--r--libc/posix/sleep.c41
-rw-r--r--libc/posix/spawn.c31
-rw-r--r--libc/posix/spawn.h190
-rw-r--r--libc/posix/spawn_faction_addclose.c53
-rw-r--r--libc/posix/spawn_faction_adddup2.c54
-rw-r--r--libc/posix/spawn_faction_addopen.c57
-rw-r--r--libc/posix/spawn_faction_destroy.c29
-rw-r--r--libc/posix/spawn_faction_init.c54
-rw-r--r--libc/posix/spawn_int.h38
-rw-r--r--libc/posix/spawnattr_destroy.c27
-rw-r--r--libc/posix/spawnattr_getdefault.c32
-rw-r--r--libc/posix/spawnattr_getflags.c30
-rw-r--r--libc/posix/spawnattr_getpgroup.c30
-rw-r--r--libc/posix/spawnattr_getschedparam.c31
-rw-r--r--libc/posix/spawnattr_getschedpolicy.c31
-rw-r--r--libc/posix/spawnattr_getsigmask.c31
-rw-r--r--libc/posix/spawnattr_init.c31
-rw-r--r--libc/posix/spawnattr_setdefault.c31
-rw-r--r--libc/posix/spawnattr_setflags.c43
-rw-r--r--libc/posix/spawnattr_setpgroup.c30
-rw-r--r--libc/posix/spawnattr_setschedparam.c31
-rw-r--r--libc/posix/spawnattr_setschedpolicy.c34
-rw-r--r--libc/posix/spawnattr_setsigmask.c31
-rw-r--r--libc/posix/spawni.c46
-rw-r--r--libc/posix/spawnp.c31
-rw-r--r--libc/posix/sys/times.h53
-rw-r--r--libc/posix/sys/types.h275
-rw-r--r--libc/posix/sys/unistd.h1
-rw-r--r--libc/posix/sys/utsname.h87
-rw-r--r--libc/posix/sys/wait.h186
-rw-r--r--libc/posix/sysconf.c273
-rw-r--r--libc/posix/tar.h108
-rw-r--r--libc/posix/test-vfork.c42
-rw-r--r--libc/posix/testcases.h167
-rw-r--r--libc/posix/testfnm.c84
-rw-r--r--libc/posix/times.c43
-rwxr-xr-xlibc/posix/transbug.c142
-rw-r--r--libc/posix/tst-boost.c227
-rw-r--r--libc/posix/tst-chmod.c378
-rw-r--r--libc/posix/tst-dir.c571
-rw-r--r--libc/posix/tst-exec.c210
-rw-r--r--libc/posix/tst-execl1.c22
-rw-r--r--libc/posix/tst-execl2.c58
-rw-r--r--libc/posix/tst-execle1.c23
-rw-r--r--libc/posix/tst-execle2.c59
-rw-r--r--libc/posix/tst-execlp1.c34
-rw-r--r--libc/posix/tst-execlp2.c82
-rw-r--r--libc/posix/tst-execv1.c22
-rw-r--r--libc/posix/tst-execv2.c60
-rw-r--r--libc/posix/tst-execve1.c23
-rw-r--r--libc/posix/tst-execve2.c61
-rw-r--r--libc/posix/tst-execvp1.c34
-rw-r--r--libc/posix/tst-execvp2.c82
-rw-r--r--libc/posix/tst-execvp3.c42
-rw-r--r--libc/posix/tst-execvp4.c35
-rw-r--r--libc/posix/tst-fnmatch.c388
-rw-r--r--libc/posix/tst-fnmatch.input755
-rw-r--r--libc/posix/tst-fork.c152
-rw-r--r--libc/posix/tst-getaddrinfo.c69
-rw-r--r--libc/posix/tst-getaddrinfo2.c77
-rw-r--r--libc/posix/tst-getaddrinfo3.c151
-rw-r--r--libc/posix/tst-getconf.sh243
-rw-r--r--libc/posix/tst-getlogin.c58
-rw-r--r--libc/posix/tst-gnuglob.c445
-rw-r--r--libc/posix/tst-mmap.c197
-rw-r--r--libc/posix/tst-nanosleep.c58
-rw-r--r--libc/posix/tst-nice.c66
-rw-r--r--libc/posix/tst-pcre.c241
-rw-r--r--libc/posix/tst-preadwrite.c105
-rw-r--r--libc/posix/tst-preadwrite64.c24
-rw-r--r--libc/posix/tst-regex.c508
-rw-r--r--libc/posix/tst-regex2.c249
-rw-r--r--libc/posix/tst-regexloc.c47
-rw-r--r--libc/posix/tst-rfc3484-2.c145
-rw-r--r--libc/posix/tst-rfc3484.c114
-rw-r--r--libc/posix/tst-rxspencer.c562
-rw-r--r--libc/posix/tst-spawn.c273
-rw-r--r--libc/posix/tst-sysconf.c114
-rw-r--r--libc/posix/tst-truncate.c133
-rw-r--r--libc/posix/tst-truncate64.c24
-rw-r--r--libc/posix/tst-vfork1.c150
-rw-r--r--libc/posix/tst-vfork2.c199
-rw-r--r--libc/posix/tst-waitid.c514
-rw-r--r--libc/posix/tstgetopt.c76
-rw-r--r--libc/posix/uname.c66
-rw-r--r--libc/posix/unistd.h1103
-rw-r--r--libc/posix/vfork.c31
-rw-r--r--libc/posix/wait.c33
-rw-r--r--libc/posix/wait.h1
-rw-r--r--libc/posix/wait3.c43
-rw-r--r--libc/posix/wait4.c33
-rw-r--r--libc/posix/waitid.c35
-rw-r--r--libc/posix/waitpid.c53
-rw-r--r--libc/posix/wordexp-test.c438
-rwxr-xr-xlibc/posix/wordexp-tst.sh153
-rw-r--r--libc/posix/wordexp.c2452
-rw-r--r--libc/posix/wordexp.h71
237 files changed, 47734 insertions, 0 deletions
diff --git a/libc/posix/.cvsignore b/libc/posix/.cvsignore
new file mode 100644
index 000000000..3fc9f4cdf
--- /dev/null
+++ b/libc/posix/.cvsignore
@@ -0,0 +1,6 @@
+*.d *.o *.so *.po *.go stamp.* *.stamp *.ustamp *.udeps
+*.gz *.Z *.tar *.tgz
+=*
+TODO COPYING* AUTHORS copyr-* copying.*
+glibc-*
+distinfo
diff --git a/libc/posix/BOOST.tests b/libc/posix/BOOST.tests
new file mode 100644
index 000000000..98fd3b6ab
--- /dev/null
+++ b/libc/posix/BOOST.tests
@@ -0,0 +1,829 @@
+;
+;
+; this file contains a script of tests to run through regress.exe
+;
+; comments start with a semicolon and proceed to the end of the line
+;
+; changes to regular expression compile flags start with a "-" as the first
+; non-whitespace character and consist of a list of the printable names
+; of the flags, for example "match_default"
+;
+; Other lines contain a test to perform using the current flag status
+; the first token contains the expression to compile, the second the string
+; to match it against. If the second string is "!" then the expression should
+; not compile, that is the first string is an invalid regular expression.
+; This is then followed by a list of integers that specify what should match,
+; each pair represents the starting and ending positions of a subexpression
+; starting with the zeroth subexpression (the whole match).
+; A value of -1 indicates that the subexpression should not take part in the
+; match at all, if the first value is -1 then no part of the expression should
+; match the string.
+;
+; Tests taken from BOOST testsuite and adapted to glibc regex.
+;
+; Boost Software License - Version 1.0 - August 17th, 2003
+;
+; Permission is hereby granted, free of charge, to any person or organization
+; obtaining a copy of the software and accompanying documentation covered by
+; this license (the "Software") to use, reproduce, display, distribute,
+; execute, and transmit the Software, and to prepare derivative works of the
+; Software, and to permit third-parties to whom the Software is furnished to
+; do so, all subject to the following:
+;
+; The copyright notices in the Software and this entire statement, including
+; the above license grant, this restriction and the following disclaimer,
+; must be included in all copies of the Software, in whole or in part, and
+; all derivative works of the Software, unless such copies or derivative
+; works are solely in the form of machine-executable object code generated by
+; a source language processor.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+; SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+; FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+; DEALINGS IN THE SOFTWARE.
+;
+
+- match_default normal REG_EXTENDED
+
+;
+; try some really simple literals:
+a a 0 1
+Z Z 0 1
+Z aaa -1 -1
+Z xxxxZZxxx 4 5
+
+; and some simple brackets:
+(a) zzzaazz 3 4 3 4
+() zzz 0 0 0 0
+() "" 0 0 0 0
+( !
+) ) 0 1
+(aa !
+aa) baa)b 1 4
+a b -1 -1
+\(\) () 0 2
+\(a\) (a) 0 3
+\() () 0 2
+(\) !
+p(a)rameter ABCparameterXYZ 3 12 4 5
+[pq](a)rameter ABCparameterXYZ 3 12 4 5
+
+; now try escaped brackets:
+- match_default bk_parens REG_BASIC
+\(a\) zzzaazz 3 4 3 4
+\(\) zzz 0 0 0 0
+\(\) "" 0 0 0 0
+\( !
+\) !
+\(aa !
+aa\) !
+() () 0 2
+(a) (a) 0 3
+(\) !
+\() !
+
+; now move on to "." wildcards
+- match_default normal REG_EXTENDED REG_STARTEND
+. a 0 1
+. \n 0 1
+. \r 0 1
+. \0 0 1
+
+;
+; now move on to the repetion ops,
+; starting with operator *
+- match_default normal REG_EXTENDED
+a* b 0 0
+ab* a 0 1
+ab* ab 0 2
+ab* sssabbbbbbsss 3 10
+ab*c* a 0 1
+ab*c* abbb 0 4
+ab*c* accc 0 4
+ab*c* abbcc 0 5
+*a !
+\<* !
+\>* !
+\n* \n\n 0 2
+\** ** 0 2
+\* * 0 1
+
+; now try operator +
+ab+ a -1 -1
+ab+ ab 0 2
+ab+ sssabbbbbbsss 3 10
+ab+c+ a -1 -1
+ab+c+ abbb -1 -1
+ab+c+ accc -1 -1
+ab+c+ abbcc 0 5
++a !
+\<+ !
+\>+ !
+\n+ \n\n 0 2
+\+ + 0 1
+\+ ++ 0 1
+\++ ++ 0 2
+
+; now try operator ?
+- match_default normal REG_EXTENDED
+a? b 0 0
+ab? a 0 1
+ab? ab 0 2
+ab? sssabbbbbbsss 3 5
+ab?c? a 0 1
+ab?c? abbb 0 2
+ab?c? accc 0 2
+ab?c? abcc 0 3
+?a !
+\<? !
+\>? !
+\n? \n\n 0 1
+\? ? 0 1
+\? ?? 0 1
+\?? ?? 0 1
+
+; now try operator {}
+- match_default normal REG_EXTENDED
+a{2} a -1 -1
+a{2} aa 0 2
+a{2} aaa 0 2
+a{2,} a -1 -1
+a{2,} aa 0 2
+a{2,} aaaaa 0 5
+a{2,4} a -1 -1
+a{2,4} aa 0 2
+a{2,4} aaa 0 3
+a{2,4} aaaa 0 4
+a{2,4} aaaaa 0 4
+a{} !
+a{2 !
+a} a} 0 2
+\{\} {} 0 2
+
+- match_default normal REG_BASIC
+a\{2\} a -1 -1
+a\{2\} aa 0 2
+a\{2\} aaa 0 2
+a\{2,\} a -1 -1
+a\{2,\} aa 0 2
+a\{2,\} aaaaa 0 5
+a\{2,4\} a -1 -1
+a\{2,4\} aa 0 2
+a\{2,4\} aaa 0 3
+a\{2,4\} aaaa 0 4
+a\{2,4\} aaaaa 0 4
+{} {} 0 2
+
+; now test the alternation operator |
+- match_default normal REG_EXTENDED
+a|b a 0 1
+a|b b 0 1
+a(b|c) ab 0 2 1 2
+a(b|c) ac 0 2 1 2
+a(b|c) ad -1 -1 -1 -1
+a\| a| 0 2
+
+; now test the set operator []
+- match_default normal REG_EXTENDED
+; try some literals first
+[abc] a 0 1
+[abc] b 0 1
+[abc] c 0 1
+[abc] d -1 -1
+[^bcd] a 0 1
+[^bcd] b -1 -1
+[^bcd] d -1 -1
+[^bcd] e 0 1
+a[b]c abc 0 3
+a[ab]c abc 0 3
+a[^ab]c adc 0 3
+a[]b]c a]c 0 3
+a[[b]c a[c 0 3
+a[-b]c a-c 0 3
+a[^]b]c adc 0 3
+a[^-b]c adc 0 3
+a[b-]c a-c 0 3
+a[b !
+a[] !
+
+; then some ranges
+[b-e] a -1 -1
+[b-e] b 0 1
+[b-e] e 0 1
+[b-e] f -1 -1
+[^b-e] a 0 1
+[^b-e] b -1 -1
+[^b-e] e -1 -1
+[^b-e] f 0 1
+a[1-3]c a2c 0 3
+a[3-1]c !
+a[1-3-5]c !
+a[1- !
+
+; and some classes
+a[[:alpha:]]c abc 0 3
+a[[:unknown:]]c !
+a[[: !
+a[[:alpha !
+a[[:alpha:] !
+a[[:alpha,:] !
+a[[:]:]]b !
+a[[:-:]]b !
+a[[:alph:]] !
+a[[:alphabet:]] !
+[[:alnum:]]+ -%@a0X_- 3 6
+[[:alpha:]]+ -%@aX_0- 3 5
+[[:blank:]]+ "a \tb" 1 4
+[[:cntrl:]]+ a\n\tb 1 3
+[[:digit:]]+ a019b 1 4
+[[:graph:]]+ " a%b " 1 4
+[[:lower:]]+ AabC 1 3
+; This test fails with STLPort, disable for now as this is a corner case anyway...
+;[[:print:]]+ "\na b\n" 1 4
+[[:punct:]]+ " %-&\t" 1 4
+[[:space:]]+ "a \n\t\rb" 1 5
+[[:upper:]]+ aBCd 1 3
+[[:xdigit:]]+ p0f3Cx 1 5
+
+; now test flag settings:
+- escape_in_lists REG_NO_POSIX_TEST
+[\n] \n 0 1
+- REG_NO_POSIX_TEST
+
+; line anchors
+- match_default normal REG_EXTENDED
+^ab ab 0 2
+^ab xxabxx -1 -1
+ab$ ab 0 2
+ab$ abxx -1 -1
+- match_default match_not_bol match_not_eol normal REG_EXTENDED REG_NOTBOL REG_NOTEOL
+^ab ab -1 -1
+^ab xxabxx -1 -1
+ab$ ab -1 -1
+ab$ abxx -1 -1
+
+; back references
+- match_default normal REG_PERL
+a(b)\2c !
+a(b\1)c !
+a(b*)c\1d abbcbbd 0 7 1 3
+a(b*)c\1d abbcbd -1 -1
+a(b*)c\1d abbcbbbd -1 -1
+^(.)\1 abc -1 -1
+a([bc])\1d abcdabbd 4 8 5 6
+; strictly speaking this is at best ambiguous, at worst wrong, this is what most
+; re implimentations will match though.
+a(([bc])\2)*d abbccd 0 6 3 5 3 4
+
+a(([bc])\2)*d abbcbd -1 -1
+a((b)*\2)*d abbbd 0 5 1 4 2 3
+; perl only:
+(ab*)[ab]*\1 ababaaa 0 7 0 1
+(a)\1bcd aabcd 0 5 0 1
+(a)\1bc*d aabcd 0 5 0 1
+(a)\1bc*d aabd 0 4 0 1
+(a)\1bc*d aabcccd 0 7 0 1
+(a)\1bc*[ce]d aabcccd 0 7 0 1
+^(a)\1b(c)*cd$ aabcccd 0 7 0 1 4 5
+
+; posix only:
+- match_default extended REG_EXTENDED
+(ab*)[ab]*\1 ababaaa 0 7 0 1
+
+;
+; word operators:
+\w a 0 1
+\w z 0 1
+\w A 0 1
+\w Z 0 1
+\w _ 0 1
+\w } -1 -1
+\w ` -1 -1
+\w [ -1 -1
+\w @ -1 -1
+; non-word:
+\W a -1 -1
+\W z -1 -1
+\W A -1 -1
+\W Z -1 -1
+\W _ -1 -1
+\W } 0 1
+\W ` 0 1
+\W [ 0 1
+\W @ 0 1
+; word start:
+\<abcd " abcd" 2 6
+\<ab cab -1 -1
+\<ab "\nab" 1 3
+\<tag ::tag 2 5
+;word end:
+abc\> abc 0 3
+abc\> abcd -1 -1
+abc\> abc\n 0 3
+abc\> abc:: 0 3
+; word boundary:
+\babcd " abcd" 2 6
+\bab cab -1 -1
+\bab "\nab" 1 3
+\btag ::tag 2 5
+abc\b abc 0 3
+abc\b abcd -1 -1
+abc\b abc\n 0 3
+abc\b abc:: 0 3
+; within word:
+\B ab 1 1
+a\Bb ab 0 2
+a\B ab 0 1
+a\B a -1 -1
+a\B "a " -1 -1
+
+;
+; buffer operators:
+\`abc abc 0 3
+\`abc \nabc -1 -1
+\`abc " abc" -1 -1
+abc\' abc 0 3
+abc\' abc\n -1 -1
+abc\' "abc " -1 -1
+
+;
+; now follows various complex expressions designed to try and bust the matcher:
+a(((b)))c abc 0 3 1 2 1 2 1 2
+a(b|(c))d abd 0 3 1 2 -1 -1
+a(b|(c))d acd 0 3 1 2 1 2
+a(b*|c)d abbd 0 4 1 3
+; just gotta have one DFA-buster, of course
+a[ab]{20} aaaaabaaaabaaaabaaaab 0 21
+; 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 0 21
+; 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 0 31 21 24 24 31
+; one really big one
+1234567890123456789012345678901234567890123456789012345678901234567890 a1234567890123456789012345678901234567890123456789012345678901234567890b 1 71
+; fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn] xacegikmoq 1 8
+[ab][cd][ef][gh][ij][kl][mn][op] xacegikmoq 1 9
+[ab][cd][ef][gh][ij][kl][mn][op][qr] xacegikmoqy 1 10
+[ab][cd][ef][gh][ij][kl][mn][op][q] xacegikmoqy 1 10
+; and as parenthesis go past 9:
+(a)(b)(c)(d)(e)(f)(g)(h) zabcdefghi 1 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9
+(a)(b)(c)(d)(e)(f)(g)(h)(i) zabcdefghij 1 10 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
+(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) zabcdefghijk 1 11 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11
+(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) zabcdefghijkl 1 12 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12
+(a)d|(b)c abc 1 3 -1 -1 1 2
+_+((www)|(ftp)|(mailto)):_* "_wwwnocolon _mailto:" 12 20 13 19 -1 -1 -1 -1 13 19
+
+; subtleties of matching
+;a(b)?c\1d acd 0 3 -1 -1
+; POSIX is about the following test:
+a(b)?c\1d acd -1 -1 -1 -1
+a(b?c)+d accd 0 4 2 3
+(wee|week)(knights|night) weeknights 0 10 0 3 3 10
+.* abc 0 3
+a(b|(c))d abd 0 3 1 2 -1 -1
+a(b|(c))d acd 0 3 1 2 1 2
+a(b*|c|e)d abbd 0 4 1 3
+a(b*|c|e)d acd 0 3 1 2
+a(b*|c|e)d ad 0 2 1 1
+a(b?)c abc 0 3 1 2
+a(b?)c ac 0 2 1 1
+a(b+)c abc 0 3 1 2
+a(b+)c abbbc 0 5 1 4
+a(b*)c ac 0 2 1 1
+(a|ab)(bc([de]+)f|cde) abcdef 0 6 0 1 1 6 3 5
+a([bc]?)c abc 0 3 1 2
+a([bc]?)c ac 0 2 1 1
+a([bc]+)c abc 0 3 1 2
+a([bc]+)c abcc 0 4 1 3
+a([bc]+)bc abcbc 0 5 1 3
+a(bb+|b)b abb 0 3 1 2
+a(bbb+|bb+|b)b abb 0 3 1 2
+a(bbb+|bb+|b)b abbb 0 4 1 3
+a(bbb+|bb+|b)bb abbb 0 4 1 2
+(.*).* abcdef 0 6 0 6
+(a*)* bc 0 0 0 0
+xyx*xz xyxxxxyxxxz 5 11
+
+; do we get the right subexpression when it is used more than once?
+a(b|c)*d ad 0 2 -1 -1
+a(b|c)*d abcd 0 4 2 3
+a(b|c)+d abd 0 3 1 2
+a(b|c)+d abcd 0 4 2 3
+a(b|c?)+d ad 0 2 1 1
+a(b|c){0,0}d ad 0 2 -1 -1
+a(b|c){0,1}d ad 0 2 -1 -1
+a(b|c){0,1}d abd 0 3 1 2
+a(b|c){0,2}d ad 0 2 -1 -1
+a(b|c){0,2}d abcd 0 4 2 3
+a(b|c){0,}d ad 0 2 -1 -1
+a(b|c){0,}d abcd 0 4 2 3
+a(b|c){1,1}d abd 0 3 1 2
+a(b|c){1,2}d abd 0 3 1 2
+a(b|c){1,2}d abcd 0 4 2 3
+a(b|c){1,}d abd 0 3 1 2
+a(b|c){1,}d abcd 0 4 2 3
+a(b|c){2,2}d acbd 0 4 2 3
+a(b|c){2,2}d abcd 0 4 2 3
+a(b|c){2,4}d abcd 0 4 2 3
+a(b|c){2,4}d abcbd 0 5 3 4
+a(b|c){2,4}d abcbcd 0 6 4 5
+a(b|c){2,}d abcd 0 4 2 3
+a(b|c){2,}d abcbd 0 5 3 4
+; perl only: these conflict with the POSIX test below
+;a(b|c?)+d abcd 0 4 3 3
+;a(b+|((c)*))+d abd 0 3 2 2 2 2 -1 -1
+;a(b+|((c)*))+d abcd 0 4 3 3 3 3 2 3
+
+; posix only:
+- match_default extended REG_EXTENDED REG_STARTEND
+
+a(b|c?)+d abcd 0 4 2 3
+a(b|((c)*))+d abcd 0 4 2 3 2 3 2 3
+a(b+|((c)*))+d abd 0 3 1 2 -1 -1 -1 -1
+a(b+|((c)*))+d abcd 0 4 2 3 2 3 2 3
+a(b|((c)*))+d ad 0 2 1 1 1 1 -1 -1
+a(b|((c)*))*d abcd 0 4 2 3 2 3 2 3
+a(b+|((c)*))*d abd 0 3 1 2 -1 -1 -1 -1
+a(b+|((c)*))*d abcd 0 4 2 3 2 3 2 3
+a(b|((c)*))*d ad 0 2 1 1 1 1 -1 -1
+
+- match_default normal REG_PERL
+; try to match C++ syntax elements:
+; line comment:
+//[^\n]* "++i //here is a line comment\n" 4 28
+; block comment:
+/\*([^*]|\*+[^*/])*\*+/ "/* here is a block comment */" 0 29 26 27
+/\*([^*]|\*+[^*/])*\*+/ "/**/" 0 4 -1 -1
+/\*([^*]|\*+[^*/])*\*+/ "/***/" 0 5 -1 -1
+/\*([^*]|\*+[^*/])*\*+/ "/****/" 0 6 -1 -1
+/\*([^*]|\*+[^*/])*\*+/ "/*****/" 0 7 -1 -1
+/\*([^*]|\*+[^*/])*\*+/ "/*****/*/" 0 7 -1 -1
+; preprossor directives:
+^[[:blank:]]*#([^\n]*\\[[:space:]]+)*[^\n]* "#define some_symbol" 0 19 -1 -1
+^[[:blank:]]*#([^\n]*\\[[:space:]]+)*[^\n]* "#define some_symbol(x) #x" 0 25 -1 -1
+; perl only:
+^[[:blank:]]*#([^\n]*\\[[:space:]]+)*[^\n]* "#define some_symbol(x) \\ \r\n foo();\\\r\n printf(#x);" 0 53 30 42
+; literals:
+((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)? 0xFF 0 4 0 4 0 4 -1 -1 -1 -1 -1 -1 -1 -1
+((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)? 35 0 2 0 2 -1 -1 0 2 -1 -1 -1 -1 -1 -1
+((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)? 0xFFu 0 5 0 4 0 4 -1 -1 -1 -1 -1 -1 -1 -1
+((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)? 0xFFL 0 5 0 4 0 4 -1 -1 4 5 -1 -1 -1 -1
+((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)? 0xFFFFFFFFFFFFFFFFuint64 0 24 0 18 0 18 -1 -1 19 24 19 24 22 24
+; strings:
+'([^\\']|\\.)*' '\\x3A' 0 6 4 5
+'([^\\']|\\.)*' '\\'' 0 4 1 3
+'([^\\']|\\.)*' '\\n' 0 4 1 3
+
+; finally try some case insensitive matches:
+- match_default normal REG_EXTENDED REG_ICASE
+; upper and lower have no meaning here so they fail, however these
+; may compile with other libraries...
+;[[:lower:]] !
+;[[:upper:]] !
+0123456789@abcdefghijklmnopqrstuvwxyz\[\\\]\^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ\{\|\} 0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\} 0 72
+
+; known and suspected bugs:
+- match_default normal REG_EXTENDED
+\( ( 0 1
+\) ) 0 1
+\$ $ 0 1
+\^ ^ 0 1
+\. . 0 1
+\* * 0 1
+\+ + 0 1
+\? ? 0 1
+\[ [ 0 1
+\] ] 0 1
+\| | 0 1
+\\ \\ 0 1
+# # 0 1
+\# # 0 1
+a- a- 0 2
+\- - 0 1
+\{ { 0 1
+\} } 0 1
+0 0 0 1
+1 1 0 1
+9 9 0 1
+b b 0 1
+B B 0 1
+< < 0 1
+> > 0 1
+w w 0 1
+W W 0 1
+` ` 0 1
+' ' 0 1
+\n \n 0 1
+, , 0 1
+a a 0 1
+f f 0 1
+n n 0 1
+r r 0 1
+t t 0 1
+v v 0 1
+c c 0 1
+x x 0 1
+: : 0 1
+(\.[[:alnum:]]+){2} "w.a.b " 1 5 3 5
+
+- match_default normal REG_EXTENDED REG_ICASE
+a A 0 1
+A a 0 1
+[abc]+ abcABC 0 6
+[ABC]+ abcABC 0 6
+[a-z]+ abcABC 0 6
+[A-Z]+ abzANZ 0 6
+[a-Z]+ abzABZ 0 6
+[A-z]+ abzABZ 0 6
+[[:lower:]]+ abyzABYZ 0 8
+[[:upper:]]+ abzABZ 0 6
+[[:alpha:]]+ abyzABYZ 0 8
+[[:alnum:]]+ 09abyzABYZ 0 10
+
+; word start:
+\<abcd " abcd" 2 6
+\<ab cab -1 -1
+\<ab "\nab" 1 3
+\<tag ::tag 2 5
+;word end:
+abc\> abc 0 3
+abc\> abcd -1 -1
+abc\> abc\n 0 3
+abc\> abc:: 0 3
+
+; collating elements and rewritten set code:
+- match_default normal REG_EXTENDED REG_STARTEND
+;[[.zero.]] 0 0 1
+;[[.one.]] 1 0 1
+;[[.two.]] 2 0 1
+;[[.three.]] 3 0 1
+[[.a.]] baa 1 2
+;[[.right-curly-bracket.]] } 0 1
+;[[.NUL.]] \0 0 1
+[[:<:]z] !
+[a[:>:]] !
+[[=a=]] a 0 1
+;[[=right-curly-bracket=]] } 0 1
+- match_default normal REG_EXTENDED REG_STARTEND REG_ICASE
+[[.A.]] A 0 1
+[[.A.]] a 0 1
+[[.A.]-b]+ AaBb 0 4
+[A-[.b.]]+ AaBb 0 4
+[[.a.]-B]+ AaBb 0 4
+[a-[.B.]]+ AaBb 0 4
+- match_default normal REG_EXTENDED REG_STARTEND
+[[.a.]-c]+ abcd 0 3
+[a-[.c.]]+ abcd 0 3
+[[:alpha:]-a] !
+[a-[:alpha:]] !
+
+; try mutli-character ligatures:
+;[[.ae.]] ae 0 2
+;[[.ae.]] aE -1 -1
+;[[.AE.]] AE 0 2
+;[[.Ae.]] Ae 0 2
+;[[.ae.]-b] a -1 -1
+;[[.ae.]-b] b 0 1
+;[[.ae.]-b] ae 0 2
+;[a-[.ae.]] a 0 1
+;[a-[.ae.]] b -1 -1
+;[a-[.ae.]] ae 0 2
+- match_default normal REG_EXTENDED REG_STARTEND REG_ICASE
+;[[.ae.]] AE 0 2
+;[[.ae.]] Ae 0 2
+;[[.AE.]] Ae 0 2
+;[[.Ae.]] aE 0 2
+;[[.AE.]-B] a -1 -1
+;[[.Ae.]-b] b 0 1
+;[[.Ae.]-b] B 0 1
+;[[.ae.]-b] AE 0 2
+
+- match_default normal REG_EXTENDED REG_STARTEND REG_NO_POSIX_TEST
+\s+ "ab ab" 2 5
+\S+ " abc " 2 5
+
+- match_default normal REG_EXTENDED REG_STARTEND
+\`abc abc 0 3
+\`abc aabc -1 -1
+abc\' abc 0 3
+abc\' abcd -1 -1
+abc\' abc\n\n -1 -1
+abc\' abc 0 3
+
+; extended repeat checking to exercise new algorithms:
+ab.*xy abxy_ 0 4
+ab.*xy ab_xy_ 0 5
+ab.*xy abxy 0 4
+ab.*xy ab_xy 0 5
+ab.* ab 0 2
+ab.* ab__ 0 4
+
+ab.{2,5}xy ab__xy_ 0 6
+ab.{2,5}xy ab____xy_ 0 8
+ab.{2,5}xy ab_____xy_ 0 9
+ab.{2,5}xy ab__xy 0 6
+ab.{2,5}xy ab_____xy 0 9
+ab.{2,5} ab__ 0 4
+ab.{2,5} ab_______ 0 7
+ab.{2,5}xy ab______xy -1 -1
+ab.{2,5}xy ab_xy -1 -1
+
+ab.*?xy abxy_ 0 4
+ab.*?xy ab_xy_ 0 5
+ab.*?xy abxy 0 4
+ab.*?xy ab_xy 0 5
+ab.*? ab 0 2
+ab.*? ab__ 0 4
+
+ab.{2,5}?xy ab__xy_ 0 6
+ab.{2,5}?xy ab____xy_ 0 8
+ab.{2,5}?xy ab_____xy_ 0 9
+ab.{2,5}?xy ab__xy 0 6
+ab.{2,5}?xy ab_____xy 0 9
+ab.{2,5}? ab__ 0 4
+ab.{2,5}? ab_______ 0 7
+ab.{2,5}?xy ab______xy -1 -1
+ab.{2,5}xy ab_xy -1 -1
+
+; again but with slower algorithm variant:
+- match_default REG_EXTENDED
+; now again for single character repeats:
+
+ab_*xy abxy_ 0 4
+ab_*xy ab_xy_ 0 5
+ab_*xy abxy 0 4
+ab_*xy ab_xy 0 5
+ab_* ab 0 2
+ab_* ab__ 0 4
+
+ab_{2,5}xy ab__xy_ 0 6
+ab_{2,5}xy ab____xy_ 0 8
+ab_{2,5}xy ab_____xy_ 0 9
+ab_{2,5}xy ab__xy 0 6
+ab_{2,5}xy ab_____xy 0 9
+ab_{2,5} ab__ 0 4
+ab_{2,5} ab_______ 0 7
+ab_{2,5}xy ab______xy -1 -1
+ab_{2,5}xy ab_xy -1 -1
+
+ab_*?xy abxy_ 0 4
+ab_*?xy ab_xy_ 0 5
+ab_*?xy abxy 0 4
+ab_*?xy ab_xy 0 5
+ab_*? ab 0 2
+ab_*? ab__ 0 4
+
+ab_{2,5}?xy ab__xy_ 0 6
+ab_{2,5}?xy ab____xy_ 0 8
+ab_{2,5}?xy ab_____xy_ 0 9
+ab_{2,5}?xy ab__xy 0 6
+ab_{2,5}?xy ab_____xy 0 9
+ab_{2,5}? ab__ 0 4
+ab_{2,5}? ab_______ 0 7
+ab_{2,5}?xy ab______xy -1 -1
+ab_{2,5}xy ab_xy -1 -1
+
+; and again for sets:
+ab[_,;]*xy abxy_ 0 4
+ab[_,;]*xy ab_xy_ 0 5
+ab[_,;]*xy abxy 0 4
+ab[_,;]*xy ab_xy 0 5
+ab[_,;]* ab 0 2
+ab[_,;]* ab__ 0 4
+
+ab[_,;]{2,5}xy ab__xy_ 0 6
+ab[_,;]{2,5}xy ab____xy_ 0 8
+ab[_,;]{2,5}xy ab_____xy_ 0 9
+ab[_,;]{2,5}xy ab__xy 0 6
+ab[_,;]{2,5}xy ab_____xy 0 9
+ab[_,;]{2,5} ab__ 0 4
+ab[_,;]{2,5} ab_______ 0 7
+ab[_,;]{2,5}xy ab______xy -1 -1
+ab[_,;]{2,5}xy ab_xy -1 -1
+
+ab[_,;]*?xy abxy_ 0 4
+ab[_,;]*?xy ab_xy_ 0 5
+ab[_,;]*?xy abxy 0 4
+ab[_,;]*?xy ab_xy 0 5
+ab[_,;]*? ab 0 2
+ab[_,;]*? ab__ 0 4
+
+ab[_,;]{2,5}?xy ab__xy_ 0 6
+ab[_,;]{2,5}?xy ab____xy_ 0 8
+ab[_,;]{2,5}?xy ab_____xy_ 0 9
+ab[_,;]{2,5}?xy ab__xy 0 6
+ab[_,;]{2,5}?xy ab_____xy 0 9
+ab[_,;]{2,5}? ab__ 0 4
+ab[_,;]{2,5}? ab_______ 0 7
+ab[_,;]{2,5}?xy ab______xy -1 -1
+ab[_,;]{2,5}xy ab_xy -1 -1
+
+; and again for tricky sets with digraphs:
+;ab[_[.ae.]]*xy abxy_ 0 4
+;ab[_[.ae.]]*xy ab_xy_ 0 5
+;ab[_[.ae.]]*xy abxy 0 4
+;ab[_[.ae.]]*xy ab_xy 0 5
+;ab[_[.ae.]]* ab 0 2
+;ab[_[.ae.]]* ab__ 0 4
+
+;ab[_[.ae.]]{2,5}xy ab__xy_ 0 6
+;ab[_[.ae.]]{2,5}xy ab____xy_ 0 8
+;ab[_[.ae.]]{2,5}xy ab_____xy_ 0 9
+;ab[_[.ae.]]{2,5}xy ab__xy 0 6
+;ab[_[.ae.]]{2,5}xy ab_____xy 0 9
+;ab[_[.ae.]]{2,5} ab__ 0 4
+;ab[_[.ae.]]{2,5} ab_______ 0 7
+;ab[_[.ae.]]{2,5}xy ab______xy -1 -1
+;ab[_[.ae.]]{2,5}xy ab_xy -1 -1
+
+;ab[_[.ae.]]*?xy abxy_ 0 4
+;ab[_[.ae.]]*?xy ab_xy_ 0 5
+;ab[_[.ae.]]*?xy abxy 0 4
+;ab[_[.ae.]]*?xy ab_xy 0 5
+;ab[_[.ae.]]*? ab 0 2
+;ab[_[.ae.]]*? ab__ 0 2
+
+;ab[_[.ae.]]{2,5}?xy ab__xy_ 0 6
+;ab[_[.ae.]]{2,5}?xy ab____xy_ 0 8
+;ab[_[.ae.]]{2,5}?xy ab_____xy_ 0 9
+;ab[_[.ae.]]{2,5}?xy ab__xy 0 6
+;ab[_[.ae.]]{2,5}?xy ab_____xy 0 9
+;ab[_[.ae.]]{2,5}? ab__ 0 4
+;ab[_[.ae.]]{2,5}? ab_______ 0 4
+;ab[_[.ae.]]{2,5}?xy ab______xy -1 -1
+;ab[_[.ae.]]{2,5}xy ab_xy -1 -1
+
+; new bugs detected in spring 2003:
+- normal match_continuous REG_NO_POSIX_TEST
+b abc 1 2
+
+() abc 0 0 0 0
+^() abc 0 0 0 0
+^()+ abc 0 0 0 0
+^(){1} abc 0 0 0 0
+^(){2} abc 0 0 0 0
+^((){2}) abc 0 0 0 0 0 0
+() "" 0 0 0 0
+()\1 "" 0 0 0 0
+()\1 a 0 0 0 0
+a()\1b ab 0 2 1 1
+a()b\1 ab 0 2 1 1
+
+; subtleties of matching with no sub-expressions marked
+- normal match_nosubs REG_NO_POSIX_TEST
+a(b?c)+d accd 0 4
+(wee|week)(knights|night) weeknights 0 10
+.* abc 0 3
+a(b|(c))d abd 0 3
+a(b|(c))d acd 0 3
+a(b*|c|e)d abbd 0 4
+a(b*|c|e)d acd 0 3
+a(b*|c|e)d ad 0 2
+a(b?)c abc 0 3
+a(b?)c ac 0 2
+a(b+)c abc 0 3
+a(b+)c abbbc 0 5
+a(b*)c ac 0 2
+(a|ab)(bc([de]+)f|cde) abcdef 0 6
+a([bc]?)c abc 0 3
+a([bc]?)c ac 0 2
+a([bc]+)c abc 0 3
+a([bc]+)c abcc 0 4
+a([bc]+)bc abcbc 0 5
+a(bb+|b)b abb 0 3
+a(bbb+|bb+|b)b abb 0 3
+a(bbb+|bb+|b)b abbb 0 4
+a(bbb+|bb+|b)bb abbb 0 4
+(.*).* abcdef 0 6
+(a*)* bc 0 0
+
+- normal nosubs REG_NO_POSIX_TEST
+a(b?c)+d accd 0 4
+(wee|week)(knights|night) weeknights 0 10
+.* abc 0 3
+a(b|(c))d abd 0 3
+a(b|(c))d acd 0 3
+a(b*|c|e)d abbd 0 4
+a(b*|c|e)d acd 0 3
+a(b*|c|e)d ad 0 2
+a(b?)c abc 0 3
+a(b?)c ac 0 2
+a(b+)c abc 0 3
+a(b+)c abbbc 0 5
+a(b*)c ac 0 2
+(a|ab)(bc([de]+)f|cde) abcdef 0 6
+a([bc]?)c abc 0 3
+a([bc]?)c ac 0 2
+a([bc]+)c abc 0 3
+a([bc]+)c abcc 0 4
+a([bc]+)bc abcbc 0 5
+a(bb+|b)b abb 0 3
+a(bbb+|bb+|b)b abb 0 3
+a(bbb+|bb+|b)b abbb 0 4
+a(bbb+|bb+|b)bb abbb 0 4
+(.*).* abcdef 0 6
+(a*)* bc 0 0
+
diff --git a/libc/posix/Depend b/libc/posix/Depend
new file mode 100644
index 000000000..f3e1156a4
--- /dev/null
+++ b/libc/posix/Depend
@@ -0,0 +1 @@
+localedata
diff --git a/libc/posix/Makefile b/libc/posix/Makefile
new file mode 100644
index 000000000..3b97ff013
--- /dev/null
+++ b/libc/posix/Makefile
@@ -0,0 +1,293 @@
+# Copyright (C) 1991-1999, 2000-2005, 2006 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+#
+# Sub-makefile for POSIX portion of the library.
+#
+subdir := posix
+
+headers := sys/utsname.h sys/times.h sys/wait.h sys/types.h unistd.h \
+ glob.h regex.h wordexp.h fnmatch.h getopt.h \
+ bits/types.h bits/typesizes.h bits/pthreadtypes.h \
+ bits/posix1_lim.h bits/posix2_lim.h bits/posix_opt.h \
+ bits/local_lim.h tar.h bits/utsname.h bits/confname.h \
+ bits/waitflags.h bits/waitstatus.h sys/unistd.h sched.h \
+ bits/sched.h re_comp.h wait.h bits/environments.h cpio.h \
+ sys/sysmacros.h spawn.h bits/unistd.h
+
+distribute := confstr.h TESTS TESTS2C.sed testcases.h \
+ PTESTS PTESTS2C.sed ptestcases.h \
+ globtest.c globtest.sh wordexp-tst.sh annexc.c fnmatch_loop.c \
+ spawn_int.h tst-getconf.sh regcomp.c regexec.c regex_internal.c \
+ regex_internal.h fork.h rxspencer/tests rxspencer/COPYRIGHT \
+ PCRE.tests BOOST.tests
+
+routines := \
+ uname \
+ times \
+ wait waitpid wait3 wait4 waitid \
+ alarm sleep pause nanosleep \
+ fork vfork _exit \
+ execve fexecve execv execle execl execvp execlp \
+ getpid getppid \
+ getuid geteuid getgid getegid getgroups setuid setgid group_member \
+ getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \
+ getresuid getresgid setresuid setresgid \
+ getlogin getlogin_r setlogin \
+ pathconf sysconf fpathconf \
+ glob glob64 fnmatch regex \
+ confstr \
+ getopt getopt1 getopt_init \
+ sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \
+ sched_primin sched_rr_gi sched_getaffinity sched_setaffinity \
+ getaddrinfo gai_strerror wordexp \
+ pread pwrite pread64 pwrite64 \
+ spawn_faction_init spawn_faction_destroy spawn_faction_addclose \
+ spawn_faction_addopen spawn_faction_adddup2 \
+ spawnattr_init spawnattr_destroy \
+ spawnattr_getdefault spawnattr_setdefault \
+ spawnattr_getflags spawnattr_setflags \
+ spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
+ spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
+ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
+ posix_madvise \
+ get_child_max
+
+include ../Makeconfig
+
+aux := init-posix environ
+tests := tstgetopt testfnm runtests runptests \
+ tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \
+ tst-getlogin tst-mmap tst-getaddrinfo tst-truncate \
+ tst-truncate64 tst-fork tst-fnmatch tst-regexloc tst-dir \
+ tst-chmod bug-regex1 bug-regex2 bug-regex3 bug-regex4 \
+ tst-gnuglob tst-regex bug-regex5 bug-regex6 bug-regex7 \
+ bug-regex8 bug-regex9 bug-regex10 bug-regex11 bug-regex12 \
+ bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+ bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+ bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+ bug-regex25 tst-nice tst-nanosleep tst-regex2 \
+ transbug tst-rxspencer tst-pcre tst-boost \
+ bug-ga1 tst-vfork1 tst-vfork2 tst-waitid \
+ tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
+ tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
+ tst-getaddrinfo3
+xtests := bug-ga2
+ifeq (yes,$(build-shared))
+test-srcs := globtest
+tests += wordexp-test tst-exec tst-spawn
+endif
+others := getconf
+install-bin := getconf
+install-others := $(inst_libexecdir)/getconf
+
+before-compile := testcases.h ptestcases.h
+
+# So they get cleaned up.
+generated := $(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 10) \
+ annexc annexc.out wordexp-tst.out bug-regex2-mem \
+ bug-regex2.mtrace bug-regex14-mem bug-regex14.mtrace \
+ bug-regex21-mem bug-regex21.mtrace \
+ tst-rxspencer-mem tst-rxspencer.mtrace tst-getconf.out \
+ tst-pcre-mem tst-pcre.mtrace tst-boost-mem tst-boost.mtrace \
+ bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem
+
+include ../Rules
+
+ifeq (yes,$(build-static-nss))
+# We need it for "make check" only. We can skip them if they haven't
+# been built yet during "make".
+otherlibs += $(wildcard $(nssobjdir)/libnss_files.a \
+ $(resolvobjdir)/libnss_dns.a \
+ $(resolvobjdir)/libresolv.a)
+endif
+
+ifeq (no,$(cross-compiling))
+# globtest and wordexp-test currently only works with shared libraries
+ifeq (yes,$(build-shared))
+tests: $(objpfx)globtest.out $(objpfx)wordexp-tst.out
+$(objpfx)globtest.out: globtest.sh $(objpfx)globtest
+ $(SHELL) -e globtest.sh $(common-objpfx) $(elf-objpfx) \
+ $(rtld-installed-name)
+$(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test
+ $(SHELL) -e wordexp-tst.sh $(common-objpfx) $(elf-objpfx) \
+ $(rtld-installed-name)
+endif
+endif
+
+CFLAGS-regex.c = -Wno-strict-prototypes
+CFLAGS-getaddrinfo.c = -DRESOLVER -fexceptions -DUSE_NSCD
+CFLAGS-pread.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pread64.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pwrite64.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sleep.c = -fexceptions
+CFLAGS-wait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-waitid.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-waitpid.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-getopt.c = -fexceptions
+CFLAGS-wordexp.c = -fexceptions
+CFLAGS-wordexp.os = -fomit-frame-pointer
+CFLAGS-sysconf.c = -fexceptions -DGETCONF_DIR='"$(libexecdir)/getconf"'
+CFLAGS-pathconf.c = -fexceptions
+CFLAGS-fpathconf.c = -fexceptions
+CFLAGS-spawn.c = -fexceptions
+CFLAGS-spawn.os = -fomit-frame-pointer
+CFLAGS-spawnp.c = -fexceptions
+CFLAGS-spawnp.os = -fomit-frame-pointer
+CFLAGS-spawni.c = -fexceptions
+CFLAGS-spawni.os = -fomit-frame-pointer
+CFLAGS-pause.c = -fexceptions
+CFLAGS-glob.c = $(uses-callbacks) -fexceptions
+CFLAGS-glob64.c = $(uses-callbacks) -fexceptions
+CFLAGS-getconf.c = -DGETCONF_DIR='"$(libexecdir)/getconf"'
+CFLAGS-execve.os = -fomit-frame-pointer
+CFLAGS-fexecve.os = -fomit-frame-pointer
+CFLAGS-execv.os = -fomit-frame-pointer
+CFLAGS-execle.os = -fomit-frame-pointer
+CFLAGS-execl.os = -fomit-frame-pointer
+CFLAGS-execvp.os = -fomit-frame-pointer
+CFLAGS-execlp.os = -fomit-frame-pointer
+
+tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \
+ --none random --col --color --colour
+
+tst-exec-ARGS = -- $(built-program-cmd)
+tst-spawn-ARGS = -- $(built-program-cmd)
+tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
+tst-chmod-ARGS = `pwd`
+
+tst-fnmatch-ENV = LOCPATH=$(common-objpfx)localedata
+tst-regexloc-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex1-ENV = LOCPATH=$(common-objpfx)localedata
+tst-regex-ENV = LOCPATH=$(common-objpfx)localedata
+tst-regex2-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex5-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex6-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex17-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex18-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex19-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex20-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex22-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex23-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex25-ENV = LOCPATH=$(common-objpfx)localedata
+tst-rxspencer-ARGS = --utf8 rxspencer/tests
+tst-rxspencer-ENV = LOCPATH=$(common-objpfx)localedata
+tst-pcre-ARGS = PCRE.tests
+tst-boost-ARGS = BOOST.tests
+bug-glob1-ARGS = "$(objpfx)"
+tst-execvp3-ARGS = --test-dir=$(objpfx)
+
+testcases.h: TESTS TESTS2C.sed
+ sed -f TESTS2C.sed < $< > $@T
+ mv -f $@T $@
+ifeq ($(with-cvs),yes)
+ test ! -d CVS || cvs $(CVSOPTS) commit -mRegenerated $@
+endif
+
+ptestcases.h: PTESTS PTESTS2C.sed
+ sed -f PTESTS2C.sed < $< > $@T
+ mv -f $@T $@
+ifeq ($(with-cvs),yes)
+ test ! -d CVS || cvs $(CVSOPTS) commit -mRegenerated $@
+endif
+
+# Run a test on the header files we use.
+# XXX Please note that for now we ignore the result of this test.
+tests: $(objpfx)annexc.out
+ifeq (no,$(cross-compiling))
+tests: $(objpfx)bug-regex2-mem $(objpfx)bug-regex14-mem \
+ $(objpfx)bug-regex21-mem $(objpfx)tst-rxspencer-mem \
+ $(objpfx)tst-pcre-mem $(objpfx)tst-boost-mem $(objpfx)tst-getconf.out \
+ $(objpfx)bug-glob2-mem
+xtests: $(objpfx)bug-ga2-mem
+endif
+
+$(objpfx)annexc.out: $(objpfx)annexc
+ -$(dir $<)$(notdir $<) '$(CC)' \
+ '$(patsubst %,-I../%,$(sorted-subdirs)) -I../include $(+sysdep-includes) $(sysincludes) -I..' > $@
+
+annexc-CFLAGS = -O
+$(objpfx)annexc: annexc.c
+ $(native-compile)
+
+bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace
+
+$(objpfx)bug-regex2-mem: $(objpfx)bug-regex2.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-regex2.mtrace > $@
+
+bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace
+
+$(objpfx)bug-regex14-mem: $(objpfx)bug-regex14.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-regex14.mtrace > $@
+
+bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace
+
+$(objpfx)bug-regex21-mem: $(objpfx)bug-regex21.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@
+
+# tst-rxspencer.mtrace is generated only when run without --utf8
+# option, since otherwise the file has almost 100M and takes very long
+# time to process.
+$(objpfx)tst-rxspencer-mem: $(objpfx)tst-rxspencer.out
+ MALLOC_TRACE=$(objpfx)tst-rxspencer.mtrace $(tst-rxspencer-ENV) \
+ $(run-program-prefix) $(objpfx)tst-rxspencer rxspencer/tests \
+ > /dev/null
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-rxspencer.mtrace > $@
+
+tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace
+$(objpfx)tst-pcre-mem: $(objpfx)tst-pcre.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-pcre.mtrace > $@
+
+tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace
+$(objpfx)tst-boost-mem: $(objpfx)tst-boost.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-boost.mtrace > $@
+
+$(objpfx)tst-getconf.out: tst-getconf.sh $(objpfx)getconf
+ $(SHELL) -e $< $(common-objpfx) $(elf-objpfx) $(rtld-installed-name)
+
+ifeq (yes,$(build-shared))
+$(objpfx)tst-regex: $(common-objpfx)rt/librt.so
+$(objpfx)tst-regex2: $(common-objpfx)rt/librt.so
+else
+$(objpfx)tst-regex: $(common-objpfx)rt/librt.a
+$(objpfx)tst-regex2: $(common-objpfx)rt/librt.a
+endif
+
+$(objpfx)bug-ga2-mem: $(objpfx)bug-ga2.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-ga2.mtrace > $@
+
+bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace
+
+bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace
+
+$(objpfx)bug-glob2-mem: $(objpfx)bug-glob2.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@
+
+$(inst_libexecdir)/getconf: $(objpfx)getconf FORCE
+ $(addprefix $(..)./scripts/mkinstalldirs ,\
+ $(filter-out $(wildcard $@),$@))
+ for spec in `LC_ALL=C GETCONF_DIR=/dev/null \
+ $(run-program-prefix) $< \
+ _POSIX_V6_WIDTH_RESTRICTED_ENVS`; do \
+ $(INSTALL_PROGRAM) $< $@/$$spec.new; \
+ mv -f $@/$$spec.new $@/$$spec; \
+ done
diff --git a/libc/posix/PCRE.tests b/libc/posix/PCRE.tests
new file mode 100644
index 000000000..0fb9cadaf
--- /dev/null
+++ b/libc/posix/PCRE.tests
@@ -0,0 +1,2386 @@
+# PCRE version 4.4 21-August-2003
+
+# Tests taken from PCRE and modified to suit glibc regex.
+#
+# PCRE LICENCE
+# ------------
+#
+# PCRE is a library of functions to support regular expressions whose syntax
+# and semantics are as close as possible to those of the Perl 5 language.
+#
+# Written by: Philip Hazel <ph10@cam.ac.uk>
+#
+# University of Cambridge Computing Service,
+# Cambridge, England. Phone: +44 1223 334714.
+#
+# Copyright (c) 1997-2003 University of Cambridge
+#
+# Permission is granted to anyone to use this software for any purpose on any
+# computer system, and to redistribute it freely, subject to the following
+# restrictions:
+#
+# 1. This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# 2. The origin of this software must not be misrepresented, either by
+# explicit claim or by omission. In practice, this means that if you use
+# PCRE in software that you distribute to others, commercially or
+# otherwise, you must put a sentence like this
+#
+# Regular expression support is provided by the PCRE library package,
+# which is open source software, written by Philip Hazel, and copyright
+# by the University of Cambridge, England.
+#
+# somewhere reasonably visible in your documentation and in any relevant
+# files or online help data or similar. A reference to the ftp site for
+# the source, that is, to
+#
+# ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
+#
+# should also be given in the documentation. However, this condition is not
+# intended to apply to whole chains of software. If package A includes PCRE,
+# it must acknowledge it, but if package B is software that includes package
+# A, the condition is not imposed on package B (unless it uses PCRE
+# independently).
+#
+# 3. Altered versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 4. If PCRE is embedded in any software that is released under the GNU
+# General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL),
+# then the terms of that licence shall supersede any condition above with
+# which it is incompatible.
+#
+# The documentation for PCRE, supplied in the "doc" directory, is distributed
+# under the same terms as the software itself.
+#
+# End
+#
+
+/the quick brown fox/
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+No match
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+No match
+
+/The quick brown fox/i
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+ 0: The quick brown FOX
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+ 0: THE QUICK BROWN FOX
+
+/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ aabxyzpqrrrabbxyyyypqAzz
+ 0: aabxyzpqrrrabbxyyyypqAzz
+ aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ aabcxyzpqrrrabbxyyyypqAzz
+ 0: aabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypAzz
+ 0: aaabcxyzpqrrrabbxyyyypAzz
+ aaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ aaaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzpqrrrabbxyyyypqAzz
+ abxyzzpqrrrabbxyyyypqAzz
+ 0: abxyzzpqrrrabbxyyyypqAzz
+ aabxyzzzpqrrrabbxyyyypqAzz
+ 0: aabxyzzzpqrrrabbxyyyypqAzz
+ aaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabxyzzzzpqrrrabbxyyyypqAzz
+ aaaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzzzzpqrrrabbxyyyypqAzz
+ abcxyzzpqrrrabbxyyyypqAzz
+ 0: abcxyzzpqrrrabbxyyyypqAzz
+ aabcxyzzzpqrrrabbxyyyypqAzz
+ 0: aabcxyzzzpqrrrabbxyyyypqAzz
+ aaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypABzz
+ 0: aaabcxyzpqrrrabbxyyyypABzz
+ aaabcxyzpqrrrabbxyyyypABBzz
+ 0: aaabcxyzpqrrrabbxyyyypABBzz
+ >>>aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ >aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ >>>>abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ *** Failers
+No match
+ abxyzpqrrabbxyyyypqAzz
+No match
+ abxyzpqrrrrabbxyyyypqAzz
+No match
+ abxyzpqrrrabxyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyypqAzz
+No match
+ aaabcxyzpqrrrabbxyyyypqqqqqqqAzz
+No match
+
+/^(abc){1,2}zz/
+ abczz
+ 0: abczz
+ 1: abc
+ abcabczz
+ 0: abcabczz
+ 1: abc
+ *** Failers
+No match
+ zz
+No match
+ abcabcabczz
+No match
+ >>abczz
+No match
+
+/^(b+|a){1,2}c/
+ bc
+ 0: bc
+ 1: b
+ bbc
+ 0: bbc
+ 1: bb
+ bbbc
+ 0: bbbc
+ 1: bbb
+ bac
+ 0: bac
+ 1: a
+ bbac
+ 0: bbac
+ 1: a
+ aac
+ 0: aac
+ 1: a
+ abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ 1: bbbbbbbbbbb
+ bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ 1: a
+ *** Failers
+No match
+ aaac
+No match
+ abbbbbbbbbbbac
+No match
+
+/^[]cde]/
+ ]thing
+ 0: ]
+ cthing
+ 0: c
+ dthing
+ 0: d
+ ething
+ 0: e
+ *** Failers
+No match
+ athing
+No match
+ fthing
+No match
+
+/^[^]cde]/
+ athing
+ 0: a
+ fthing
+ 0: f
+ *** Failers
+ 0: *
+ ]thing
+No match
+ cthing
+No match
+ dthing
+No match
+ ething
+No match
+
+/^[0-9]+$/
+ 0
+ 0: 0
+ 1
+ 0: 1
+ 2
+ 0: 2
+ 3
+ 0: 3
+ 4
+ 0: 4
+ 5
+ 0: 5
+ 6
+ 0: 6
+ 7
+ 0: 7
+ 8
+ 0: 8
+ 9
+ 0: 9
+ 10
+ 0: 10
+ 100
+ 0: 100
+ *** Failers
+No match
+ abc
+No match
+
+/^.*nter/
+ enter
+ 0: enter
+ inter
+ 0: inter
+ uponter
+ 0: uponter
+
+/^xxx[0-9]+$/
+ xxx0
+ 0: xxx0
+ xxx1234
+ 0: xxx1234
+ *** Failers
+No match
+ xxx
+No match
+
+/^.+[0-9][0-9][0-9]$/
+ x123
+ 0: x123
+ xx123
+ 0: xx123
+ 123456
+ 0: 123456
+ *** Failers
+No match
+ 123
+No match
+ x1234
+ 0: x1234
+
+/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/
+ abc!pqr=apquxz.ixr.zzz.ac.uk
+ 0: abc!pqr=apquxz.ixr.zzz.ac.uk
+ 1: abc
+ 2: pqr
+ *** Failers
+No match
+ !pqr=apquxz.ixr.zzz.ac.uk
+No match
+ abc!=apquxz.ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz:ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz.ixr.zzz.ac.ukk
+No match
+
+/:/
+ Well, we need a colon: somewhere
+ 0: :
+ *** Fail if we don't
+No match
+
+/([0-9a-f:]+)$/i
+ 0abc
+ 0: 0abc
+ 1: 0abc
+ abc
+ 0: abc
+ 1: abc
+ fed
+ 0: fed
+ 1: fed
+ E
+ 0: E
+ 1: E
+ ::
+ 0: ::
+ 1: ::
+ 5f03:12C0::932e
+ 0: 5f03:12C0::932e
+ 1: 5f03:12C0::932e
+ fed def
+ 0: def
+ 1: def
+ Any old stuff
+ 0: ff
+ 1: ff
+ *** Failers
+No match
+ 0zzz
+No match
+ gzzz
+No match
+ Any old rubbish
+No match
+
+/^.*\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/
+ .1.2.3
+ 0: .1.2.3
+ 1: 1
+ 2: 2
+ 3: 3
+ A.12.123.0
+ 0: A.12.123.0
+ 1: 12
+ 2: 123
+ 3: 0
+ *** Failers
+No match
+ .1.2.3333
+No match
+ 1.2.3
+No match
+ 1234.2.3
+No match
+
+/^([0-9]+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/
+ 1 IN SOA non-sp1 non-sp2(
+ 0: 1 IN SOA non-sp1 non-sp2(
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+ 1 IN SOA non-sp1 non-sp2 (
+ 0: 1 IN SOA non-sp1 non-sp2 (
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+ *** Failers
+No match
+ 1IN SOA non-sp1 non-sp2(
+No match
+
+/^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-z0-9-]*)*\.$/
+ a.
+ 0: a.
+ Z.
+ 0: Z.
+ 2.
+ 0: 2.
+ ab-c.pq-r.
+ 0: ab-c.pq-r.
+ 1: .pq-r
+ sxk.zzz.ac.uk.
+ 0: sxk.zzz.ac.uk.
+ 1: .uk
+ x-.y-.
+ 0: x-.y-.
+ 1: .y-
+ *** Failers
+No match
+ -abc.peq.
+No match
+
+/^\*\.[a-z]([a-z0-9-]*[a-z0-9]+)?(\.[a-z]([a-z0-9-]*[a-z0-9]+)?)*$/
+ *.a
+ 0: *.a
+ *.b0-a
+ 0: *.b0-a
+ 1: 0-a
+ *.c3-b.c
+ 0: *.c3-b.c
+ 1: 3-b
+ 2: .c
+ *.c-a.b-c
+ 0: *.c-a.b-c
+ 1: -a
+ 2: .b-c
+ 3: -c
+ *** Failers
+No match
+ *.0
+No match
+ *.a-
+No match
+ *.a-b.c-
+No match
+ *.c-a.0-c
+No match
+
+/^[0-9a-f](\.[0-9a-f])*$/i
+ a.b.c.d
+ 0: a.b.c.d
+ 1: .d
+ A.B.C.D
+ 0: A.B.C.D
+ 1: .D
+ a.b.c.1.2.3.C
+ 0: a.b.c.1.2.3.C
+ 1: .C
+
+/^".*"\s*(;.*)?$/
+ "1234"
+ 0: "1234"
+ "abcd" ;
+ 0: "abcd" ;
+ 1: ;
+ "" ; rhubarb
+ 0: "" ; rhubarb
+ 1: ; rhubarb
+ *** Failers
+No match
+ "1234" : things
+No match
+
+/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/
+ abcdefhijklm
+ 0: abcdefhijklm
+ 1: abc
+ 2: bc
+ 3: c
+ 4: def
+ 5: ef
+ 6: f
+ 7: hij
+ 8: ij
+ 9: j
+10: klm
+11: lm
+12: m
+
+/^a*\w/
+ z
+ 0: z
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ a
+ 0: a
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ a+
+ 0: a
+ aa+
+ 0: aa
+
+/^a+\w/
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ aa+
+ 0: aa
+
+/^[0-9]{8}\w{2,}/
+ 1234567890
+ 0: 1234567890
+ 12345678ab
+ 0: 12345678ab
+ 12345678__
+ 0: 12345678__
+ *** Failers
+No match
+ 1234567
+No match
+
+/^[aeiou0-9]{4,5}$/
+ uoie
+ 0: uoie
+ 1234
+ 0: 1234
+ 12345
+ 0: 12345
+ aaaaa
+ 0: aaaaa
+ *** Failers
+No match
+ 123456
+No match
+
+/\`(abc|def)=(\1){2,3}\'/
+ abc=abcabc
+ 0: abc=abcabc
+ 1: abc
+ 2: abc
+ def=defdefdef
+ 0: def=defdefdef
+ 1: def
+ 2: def
+ *** Failers
+No match
+ abc=defdef
+No match
+
+/(cat(a(ract|tonic)|erpillar)) \1()2(3)/
+ cataract cataract23
+ 0: cataract cataract23
+ 1: cataract
+ 2: aract
+ 3: ract
+ 4:
+ 5: 3
+ catatonic catatonic23
+ 0: catatonic catatonic23
+ 1: catatonic
+ 2: atonic
+ 3: tonic
+ 4:
+ 5: 3
+ caterpillar caterpillar23
+ 0: caterpillar caterpillar23
+ 1: caterpillar
+ 2: erpillar
+ 3: <unset>
+ 4:
+ 5: 3
+
+
+/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+ 1: abcd
+
+/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}[0-9]{1,2}\s+[0-9][0-9]:[0-9][0-9]/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+ 1: Sep
+ From abcd Mon Sep 1 12:33:02 1997
+ 0: From abcd Mon Sep 1 12:33
+ 1: Sep
+ *** Failers
+No match
+ From abcd Sep 01 12:33:02 1997
+No match
+
+/^(a)\1{2,3}(.)/
+ aaab
+ 0: aaab
+ 1: a
+ 2: b
+ aaaab
+ 0: aaaab
+ 1: a
+ 2: b
+ aaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+ aaaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+
+/^[ab]{1,3}(ab*|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: abbbbb
+
+/^(cow|)\1(bell)/
+ cowcowbell
+ 0: cowcowbell
+ 1: cow
+ 2: bell
+ bell
+ 0: bell
+ 1:
+ 2: bell
+ *** Failers
+No match
+ cowbell
+No match
+
+/^(a|)\1+b/
+ aab
+ 0: aab
+ 1: a
+ aaaab
+ 0: aaaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+
+/^(a|)\1{2}b/
+ aaab
+ 0: aaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+ aab
+No match
+ aaaab
+No match
+
+/^(a|)\1{2,3}b/
+ aaab
+ 0: aaab
+ 1: a
+ aaaab
+ 0: aaaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+ aab
+No match
+ aaaaab
+No match
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+ abbbc
+ 0: abbbc
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abbbbbc
+No match
+
+/([^.]*)\.([^:]*):[T ]+(.*)/
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[T ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[t ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+
+/[-az]+/
+ az-
+ 0: az-
+ *** Failers
+ 0: a
+ b
+No match
+
+/[az-]+/
+ za-
+ 0: za-
+ *** Failers
+ 0: a
+ b
+No match
+
+/[a-z]+/
+ abcdxyz
+ 0: abcdxyz
+
+/[0-9-]+/
+ 12-34
+ 0: 12-34
+ *** Failers
+No match
+ aaa
+No match
+
+/(abc)\1/i
+ abcabc
+ 0: abcabc
+ 1: abc
+ ABCabc
+ 0: ABCabc
+ 1: ABC
+ abcABC
+ 0: abcABC
+ 1: abc
+
+/a{0}bc/
+ bc
+ 0: bc
+
+/^([^a])([^b])([^c]*)([^d]{3,4})/
+ baNOTccccd
+ 0: baNOTcccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: cccc
+ baNOTcccd
+ 0: baNOTccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: ccc
+ baNOTccd
+ 0: baNOTcc
+ 1: b
+ 2: a
+ 3: NO
+ 4: Tcc
+ bacccd
+ 0: baccc
+ 1: b
+ 2: a
+ 3:
+ 4: ccc
+ *** Failers
+ 0: *** Failers
+ 1: *
+ 2: *
+ 3: * Fail
+ 4: ers
+ anything
+No match
+ baccd
+No match
+
+/[^a]/
+ Abc
+ 0: A
+
+/[^a]/i
+ Abc
+ 0: b
+
+/[^a]+/
+ AAAaAbc
+ 0: AAA
+
+/[^a]+/i
+ AAAaAbc
+ 0: bc
+
+/[^k]$/
+ abc
+ 0: c
+ *** Failers
+ 0: s
+ abk
+No match
+
+/[^k]{2,3}$/
+ abc
+ 0: abc
+ kbc
+ 0: bc
+ kabc
+ 0: abc
+ *** Failers
+ 0: ers
+ abk
+No match
+ akb
+No match
+ akk
+No match
+
+/^[0-9]{8,}@.+[^k]$/
+ 12345678@a.b.c.d
+ 0: 12345678@a.b.c.d
+ 123456789@x.y.z
+ 0: 123456789@x.y.z
+ *** Failers
+No match
+ 12345678@x.y.uk
+No match
+ 1234567@a.b.c.d
+No match
+
+/(a)\1{8,}/
+ aaaaaaaaa
+ 0: aaaaaaaaa
+ 1: a
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: a
+ *** Failers
+No match
+ aaaaaaa
+No match
+
+/[^a]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^a]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/[^az]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^az]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/P[^*]TAIRE[^*]{1,6}LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/P[^*]TAIRE[^*]{1,}LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/(\.[0-9][0-9][1-9]?)[0-9]+/
+ 1.230003938
+ 0: .230003938
+ 1: .23
+ 1.875000282
+ 0: .875000282
+ 1: .875
+ 1.235
+ 0: .235
+ 1: .23
+
+/\b(foo)\s+(\w+)/i
+ Food is on the foo table
+ 0: foo table
+ 1: foo
+ 2: table
+
+/foo(.*)bar/
+ The food is under the bar in the barn.
+ 0: food is under the bar in the bar
+ 1: d is under the bar in the
+
+/(.*)([0-9]*)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 53147
+ 2:
+
+/(.*)([0-9]+)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+
+/(.*)([0-9]+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+
+/(.*)\b([0-9]+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers:
+ 2: 53147
+
+/(.*[^0-9])([0-9]+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers:
+ 2: 53147
+
+/[[:digit:]][[:digit:]]\/[[:digit:]][[:digit:]]\/[[:digit:]][[:digit:]][[:digit:]][[:digit:]]/
+ 01/01/2000
+ 0: 01/01/2000
+
+/^(a){0,0}/
+ bcd
+ 0:
+ abc
+ 0:
+ aab
+ 0:
+
+/^(a){0,1}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: a
+ 1: a
+
+/^(a){0,2}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+
+/^(a){0,3}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+
+/^(a){0,}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: a
+
+/^(a){1,1}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: a
+ 1: a
+
+/^(a){1,2}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+
+/^(a){1,3}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+
+/^(a){1,}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: a
+
+/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
+ 123456654321
+ 0: 123456654321
+
+/^[[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]/
+ 123456654321
+ 0: 123456654321
+
+/^[abc]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^[a-c]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^(a|b|c){12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+ 1: c
+
+/^[abcdefghijklmnopqrstuvwxy0123456789]/
+ n
+ 0: n
+ *** Failers
+No match
+ z
+No match
+
+/abcde{0,0}/
+ abcd
+ 0: abcd
+ *** Failers
+No match
+ abce
+No match
+
+/ab[cd]{0,0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ abcde
+No match
+
+/ab(c){0,0}d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ abcd
+No match
+
+/a(b*)/
+ a
+ 0: a
+ 1:
+ ab
+ 0: ab
+ 1: b
+ abbbb
+ 0: abbbb
+ 1: bbbb
+ *** Failers
+ 0: a
+ 1:
+ bbbbb
+No match
+
+/ab[0-9]{0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ ab1e
+No match
+
+/(A|B)*CD/
+ CD
+ 0: CD
+
+/(AB)*\1/
+ ABABAB
+ 0: ABABAB
+ 1: AB
+
+/([0-9]+)(\w)/
+ 12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+ 12345+
+ 0: 12345
+ 1: 1234
+ 2: 5
+
+/(abc|)+/
+ abc
+ 0: abc
+ 1: abc
+ abcabc
+ 0: abcabc
+ 1: abc
+ abcabcabc
+ 0: abcabcabc
+ 1: abc
+ xyz
+ 0:
+ 1:
+
+/([a]*)*/
+ a
+ 0: a
+ 1: a
+ aaaaa
+ 0: aaaaa
+ 1: aaaaa
+
+/([ab]*)*/
+ a
+ 0: a
+ 1: a
+ b
+ 0: b
+ 1: b
+ ababab
+ 0: ababab
+ 1: ababab
+ aaaabcde
+ 0: aaaab
+ 1: aaaab
+ bbbb
+ 0: bbbb
+ 1: bbbb
+
+/([^a]*)*/
+ b
+ 0: b
+ 1: b
+ bbbb
+ 0: bbbb
+ 1: bbbb
+ aaa
+ 0:
+
+/([^ab]*)*/
+ cccc
+ 0: cccc
+ 1: cccc
+ abab
+ 0:
+
+/abc/
+ abc
+ 0: abc
+ xabcy
+ 0: abc
+ ababc
+ 0: abc
+ *** Failers
+No match
+ xbc
+No match
+ axc
+No match
+ abx
+No match
+
+/ab*c/
+ abc
+ 0: abc
+
+/ab*bc/
+ abc
+ 0: abc
+ abbc
+ 0: abbc
+ abbbbc
+ 0: abbbbc
+
+/.{1}/
+ abbbbc
+ 0: a
+
+/.{3,4}/
+ abbbbc
+ 0: abbb
+
+/ab{0,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab+bc/
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abq
+No match
+
+/ab+bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{3,4}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{4,5}bc/
+ *** Failers
+No match
+ abq
+No match
+ abbbbc
+No match
+
+/ab?bc/
+ abbc
+ 0: abbc
+ abc
+ 0: abc
+
+/ab{0,1}bc/
+ abc
+ 0: abc
+
+/ab?c/
+ abc
+ 0: abc
+
+/ab{0,1}c/
+ abc
+ 0: abc
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+ abbbbc
+No match
+ abcc
+No match
+
+/^abc/
+ abcc
+ 0: abc
+
+/abc$/
+ aabc
+ 0: abc
+ *** Failers
+No match
+ aabc
+ 0: abc
+ aabcd
+No match
+
+/^/
+ abc
+ 0:
+
+/$/
+ abc
+ 0:
+
+/a.c/
+ abc
+ 0: abc
+ axc
+ 0: axc
+
+/a.*c/
+ axyzc
+ 0: axyzc
+
+/a[bc]d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ axyzd
+No match
+ abc
+No match
+
+/a[b-d]e/
+ ace
+ 0: ace
+
+/a[b-d]/
+ aac
+ 0: ac
+
+/a[-b]/
+ a-
+ 0: a-
+
+/a[b-]/
+ a-
+ 0: a-
+
+/a[]]b/
+ a]b
+ 0: a]b
+
+/a[^bc]d/
+ aed
+ 0: aed
+ *** Failers
+No match
+ abd
+No match
+ abd
+No match
+
+/a[^-b]c/
+ adc
+ 0: adc
+
+/a[^]b]c/
+ adc
+ 0: adc
+ *** Failers
+No match
+ a-c
+ 0: a-c
+ a]c
+No match
+
+/\ba\b/
+ a-
+ 0: a
+ -a
+ 0: a
+ -a-
+ 0: a
+
+/\by\b/
+ *** Failers
+No match
+ xy
+No match
+ yz
+No match
+ xyz
+No match
+
+/\Ba\B/
+ *** Failers
+ 0: a
+ a-
+No match
+ -a
+No match
+ -a-
+No match
+
+/\By\b/
+ xy
+ 0: y
+
+/\by\B/
+ yz
+ 0: y
+
+/\By\B/
+ xyz
+ 0: y
+
+/\w/
+ a
+ 0: a
+
+/\W/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ a
+No match
+
+/a\sb/
+ a b
+ 0: a b
+
+/a\Sb/
+ a-b
+ 0: a-b
+ *** Failers
+No match
+ a-b
+ 0: a-b
+ a b
+No match
+
+/[0-9]/
+ 1
+ 0: 1
+
+/[^0-9]/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ 1
+No match
+
+/ab|cd/
+ abc
+ 0: ab
+ abcd
+ 0: ab
+
+/()ef/
+ def
+ 0: ef
+ 1:
+
+/a\(b/
+ a(b
+ 0: a(b
+
+/a\(*b/
+ ab
+ 0: ab
+ a((b
+ 0: a((b
+
+/((a))/
+ abc
+ 0: a
+ 1: a
+ 2: a
+
+/(a)b(c)/
+ abc
+ 0: abc
+ 1: a
+ 2: c
+
+/a+b+c/
+ aabbabc
+ 0: abc
+
+/a{1,}b{1,}c/
+ aabbabc
+ 0: abc
+
+/(a+|b)*/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b){0,}/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b)+/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b){1,}/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b)?/
+ ab
+ 0: a
+ 1: a
+
+/(a+|b){0,1}/
+ ab
+ 0: a
+ 1: a
+
+/[^ab]*/
+ cde
+ 0: cde
+
+/abc/
+ *** Failers
+No match
+ b
+No match
+
+
+/a*/
+
+
+/([abc])*d/
+ abbbcd
+ 0: abbbcd
+ 1: c
+
+/([abc])*bcd/
+ abcd
+ 0: abcd
+ 1: a
+
+/a|b|c|d|e/
+ e
+ 0: e
+
+/(a|b|c|d|e)f/
+ ef
+ 0: ef
+ 1: e
+
+/abcd*efg/
+ abcdefg
+ 0: abcdefg
+
+/ab*/
+ xabyabbbz
+ 0: ab
+ xayabbbz
+ 0: a
+
+/(ab|cd)e/
+ abcde
+ 0: cde
+ 1: cd
+
+/[abhgefdc]ij/
+ hij
+ 0: hij
+
+/(abc|)ef/
+ abcdef
+ 0: ef
+ 1:
+
+/(a|b)c*d/
+ abcd
+ 0: bcd
+ 1: b
+
+/(ab|ab*)bc/
+ abc
+ 0: abc
+ 1: a
+
+/a([bc]*)c*/
+ abc
+ 0: abc
+ 1: bc
+
+/a([bc]*)(c*d)/
+ abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]+)(c*d)/
+ abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]*)(c+d)/
+ abcd
+ 0: abcd
+ 1: b
+ 2: cd
+
+/a[bcd]*dcdcde/
+ adcdcde
+ 0: adcdcde
+
+/a[bcd]+dcdcde/
+ *** Failers
+No match
+ abcde
+No match
+ adcdcde
+No match
+
+/(ab|a)b*c/
+ abc
+ 0: abc
+ 1: ab
+
+/((a)(b)c)(d)/
+ abcd
+ 0: abcd
+ 1: abc
+ 2: a
+ 3: b
+ 4: d
+
+/[a-zA-Z_][a-zA-Z0-9_]*/
+ alpha
+ 0: alpha
+
+/^a(bc+|b[eh])g|.h$/
+ abh
+ 0: bh
+
+/(bc+d$|ef*g.|h?i(j|k))/
+ effgz
+ 0: effgz
+ 1: effgz
+ ij
+ 0: ij
+ 1: ij
+ 2: j
+ reffgz
+ 0: effgz
+ 1: effgz
+ *** Failers
+No match
+ effg
+No match
+ bcdd
+No match
+
+/((((((((((a))))))))))/
+ a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/((((((((((a))))))))))\9/
+ aa
+ 0: aa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/(((((((((a)))))))))/
+ a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+
+/multiple words of text/
+ *** Failers
+No match
+ aa
+No match
+ uh-uh
+No match
+
+/multiple words/
+ multiple words, yeah
+ 0: multiple words
+
+/(.*)c(.*)/
+ abcde
+ 0: abcde
+ 1: ab
+ 2: de
+
+/\((.*), (.*)\)/
+ (a, b)
+ 0: (a, b)
+ 1: a
+ 2: b
+
+/abcd/
+ abcd
+ 0: abcd
+
+/a(bc)d/
+ abcd
+ 0: abcd
+ 1: bc
+
+/a[-]?c/
+ ac
+ 0: ac
+
+/(abc)\1/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/([a-c]*)\1/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/(a)|\1/
+ a
+ 0: a
+ 1: a
+ *** Failers
+ 0: a
+ 1: a
+ ab
+ 0: a
+ 1: a
+ x
+No match
+
+/abc/i
+ ABC
+ 0: ABC
+ XABCY
+ 0: ABC
+ ABABC
+ 0: ABC
+ *** Failers
+No match
+ aaxabxbaxbbx
+No match
+ XBC
+No match
+ AXC
+No match
+ ABX
+No match
+
+/ab*c/i
+ ABC
+ 0: ABC
+
+/ab*bc/i
+ ABC
+ 0: ABC
+ ABBC
+ 0: ABBC
+
+/ab+bc/i
+ *** Failers
+No match
+ ABC
+No match
+ ABQ
+No match
+
+/ab+bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/^abc$/i
+ ABC
+ 0: ABC
+ *** Failers
+No match
+ ABBBBC
+No match
+ ABCC
+No match
+
+/^abc/i
+ ABCC
+ 0: ABC
+
+/abc$/i
+ AABC
+ 0: ABC
+
+/^/i
+ ABC
+ 0:
+
+/$/i
+ ABC
+ 0:
+
+/a.c/i
+ ABC
+ 0: ABC
+ AXC
+ 0: AXC
+
+/a.*c/i
+ *** Failers
+No match
+ AABC
+ 0: AABC
+ AXYZD
+No match
+
+/a[bc]d/i
+ ABD
+ 0: ABD
+
+/a[b-d]e/i
+ ACE
+ 0: ACE
+ *** Failers
+No match
+ ABC
+No match
+ ABD
+No match
+
+/a[b-d]/i
+ AAC
+ 0: AC
+
+/a[-b]/i
+ A-
+ 0: A-
+
+/a[b-]/i
+ A-
+ 0: A-
+
+/a[]]b/i
+ A]B
+ 0: A]B
+
+/a[^bc]d/i
+ AED
+ 0: AED
+
+/a[^-b]c/i
+ ADC
+ 0: ADC
+ *** Failers
+No match
+ ABD
+No match
+ A-C
+No match
+
+/a[^]b]c/i
+ ADC
+ 0: ADC
+
+/ab|cd/i
+ ABC
+ 0: AB
+ ABCD
+ 0: AB
+
+/()ef/i
+ DEF
+ 0: EF
+ 1:
+
+/$b/i
+ *** Failers
+No match
+ A]C
+No match
+ B
+No match
+
+/a\(b/i
+ A(B
+ 0: A(B
+
+/a\(*b/i
+ AB
+ 0: AB
+ A((B
+ 0: A((B
+
+/((a))/i
+ ABC
+ 0: A
+ 1: A
+ 2: A
+
+/(a)b(c)/i
+ ABC
+ 0: ABC
+ 1: A
+ 2: C
+
+/a+b+c/i
+ AABBABC
+ 0: ABC
+
+/a{1,}b{1,}c/i
+ AABBABC
+ 0: ABC
+
+/(a+|b)*/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b){0,}/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b)+/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b){1,}/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b)?/i
+ AB
+ 0: A
+ 1: A
+
+/(a+|b){0,1}/i
+ AB
+ 0: A
+ 1: A
+
+/[^ab]*/i
+ CDE
+ 0: CDE
+
+/([abc])*d/i
+ ABBBCD
+ 0: ABBBCD
+ 1: C
+
+/([abc])*bcd/i
+ ABCD
+ 0: ABCD
+ 1: A
+
+/a|b|c|d|e/i
+ E
+ 0: E
+
+/(a|b|c|d|e)f/i
+ EF
+ 0: EF
+ 1: E
+
+/abcd*efg/i
+ ABCDEFG
+ 0: ABCDEFG
+
+/ab*/i
+ XABYABBBZ
+ 0: AB
+ XAYABBBZ
+ 0: A
+
+/(ab|cd)e/i
+ ABCDE
+ 0: CDE
+ 1: CD
+
+/[abhgefdc]ij/i
+ HIJ
+ 0: HIJ
+
+/^(ab|cd)e/i
+ ABCDE
+No match
+
+/(abc|)ef/i
+ ABCDEF
+ 0: EF
+ 1:
+
+/(a|b)c*d/i
+ ABCD
+ 0: BCD
+ 1: B
+
+/(ab|ab*)bc/i
+ ABC
+ 0: ABC
+ 1: A
+
+/a([bc]*)c*/i
+ ABC
+ 0: ABC
+ 1: BC
+
+/a([bc]*)(c*d)/i
+ ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]+)(c*d)/i
+ ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]*)(c+d)/i
+ ABCD
+ 0: ABCD
+ 1: B
+ 2: CD
+
+/a[bcd]*dcdcde/i
+ ADCDCDE
+ 0: ADCDCDE
+
+/a[bcd]+dcdcde/i
+
+/(ab|a)b*c/i
+ ABC
+ 0: ABC
+ 1: AB
+
+/((a)(b)c)(d)/i
+ ABCD
+ 0: ABCD
+ 1: ABC
+ 2: A
+ 3: B
+ 4: D
+
+/[a-zA-Z_][a-zA-Z0-9_]*/i
+ ALPHA
+ 0: ALPHA
+
+/^a(bc+|b[eh])g|.h$/i
+ ABH
+ 0: BH
+
+/(bc+d$|ef*g.|h?i(j|k))/i
+ EFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+ IJ
+ 0: IJ
+ 1: IJ
+ 2: J
+ REFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+ *** Failers
+No match
+ ADCDCDE
+No match
+ EFFG
+No match
+ BCDD
+No match
+
+/((((((((((a))))))))))/i
+ A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/((((((((((a))))))))))\9/i
+ AA
+ 0: AA
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/(((((((((a)))))))))/i
+ A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+
+/multiple words of text/i
+ *** Failers
+No match
+ AA
+No match
+ UH-UH
+No match
+
+/multiple words/i
+ MULTIPLE WORDS, YEAH
+ 0: MULTIPLE WORDS
+
+/(.*)c(.*)/i
+ ABCDE
+ 0: ABCDE
+ 1: AB
+ 2: DE
+
+/\((.*), (.*)\)/i
+ (A, B)
+ 0: (A, B)
+ 1: A
+ 2: B
+
+/abcd/i
+ ABCD
+ 0: ABCD
+
+/a(bc)d/i
+ ABCD
+ 0: ABCD
+ 1: BC
+
+/a[-]?c/i
+ AC
+ 0: AC
+
+/(abc)\1/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/([a-c]*)\1/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/((foo)|(bar))*/
+ foobar
+ 0: foobar
+ 1: bar
+ 2: foo
+ 3: bar
+
+/^(.+)?B/
+ AB
+ 0: AB
+ 1: A
+
+/^([^a-z])|(\^)$/
+ .
+ 0: .
+ 1: .
+
+/^[<>]&/
+ <&OUT
+ 0: <&
+
+/^(){3,5}/
+ abc
+ 0:
+ 1:
+
+/^(a+)*ax/
+ aax
+ 0: aax
+ 1: a
+
+/^((a|b)+)*ax/
+ aax
+ 0: aax
+ 1: a
+ 2: a
+
+/^((a|bc)+)*ax/
+ aax
+ 0: aax
+ 1: a
+ 2: a
+
+/(a|x)*ab/
+ cab
+ 0: ab
+
+/(a)*ab/
+ cab
+ 0: ab
+
+/(ab)[0-9]\1/i
+ Ab4ab
+ 0: Ab4ab
+ 1: Ab
+ ab4Ab
+ 0: ab4Ab
+ 1: ab
+
+/foo\w*[0-9]{4}baz/
+ foobar1234baz
+ 0: foobar1234baz
+
+/(\w+:)+/
+ one:
+ 0: one:
+ 1: one:
+
+/((\w|:)+::)?(\w+)$/
+ abcd
+ 0: abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: :
+ 3: abcd
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+ 1: c
+
+/(a*)b+/
+ caab
+ 0: aab
+ 1: aa
+
+/((\w|:)+::)?(\w+)$/
+ abcd
+ 0: abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: :
+ 3: abcd
+ *** Failers
+ 0: Failers
+ 1: <unset>
+ 2: <unset>
+ 3: Failers
+ abcd:
+No match
+ abcd:
+No match
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+ 1: c
+
+/((Z)+|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2: Z
+
+/(Z()|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2:
+
+/(Z(())|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2:
+ 3:
+
+/(.*)[0-9]+\1/
+ abc123abc
+ 0: abc123abc
+ 1: abc
+ abc123bc
+ 0: bc123bc
+ 1: bc
+
+/((.*))[0-9]+\1/
+ abc123abc
+ 0: abc123abc
+ 1: abc
+ 2: abc
+ abc123bc
+ 0: bc123bc
+ 1: bc
+ 2: bc
+
+/^a{2,5}$/
+ aa
+ 0: aa
+ aaa
+ 0: aaa
+ aaaa
+ 0: aaaa
+ aaaaa
+ 0: aaaaa
+ *** Failers
+No match
+ a
+No match
+ b
+No match
+ aaaaab
+No match
+ aaaaaa
diff --git a/libc/posix/PTESTS b/libc/posix/PTESTS
new file mode 100644
index 000000000..02b357cf2
--- /dev/null
+++ b/libc/posix/PTESTS
@@ -0,0 +1,341 @@
+# 2.8.2 Regular Expression General Requirement
+2¦4¦bb*¦abbbc¦
+2¦2¦bb*¦ababbbc¦
+7¦9¦A#*::¦A:A#:qA::qA#::qA##::q¦
+1¦5¦A#*::¦A##::A#::qA::qA#:q¦
+# 2.8.3.1.2 BRE Special Characters
+# GA108
+2¦2¦\.¦a.c¦
+2¦2¦\[¦a[c¦
+2¦2¦\\¦a\c¦
+2¦2¦\*¦a*c¦
+2¦2¦\^¦a^c¦
+2¦2¦\$¦a$c¦
+7¦11¦X\*Y\*8¦Y*8X*8X*Y*8¦
+# GA109
+2¦2¦[.]¦a.c¦
+2¦2¦[[]¦a[c¦
+-1¦-1¦[[]¦ac¦
+2¦2¦[\]¦a\c¦
+1¦1¦[\a]¦abc¦
+2¦2¦[\.]¦a\.c¦
+2¦2¦[\.]¦a.\c¦
+2¦2¦[*]¦a*c¦
+2¦2¦[$]¦a$c¦
+2¦2¦[X*Y8]¦7*8YX¦
+# GA110
+2¦2¦*¦a*c¦
+3¦4¦*a¦*b*a*c¦
+1¦5¦**9=¦***9=9¦
+# GA111
+1¦1¦^*¦*bc¦
+-1¦-1¦^*¦a*c¦
+-1¦-1¦^*¦^*ab¦
+1¦5¦^**9=¦***9=¦
+-1¦-1¦^*5<*9¦5<9*5<*9¦
+# GA112
+2¦3¦\(*b\)¦a*b¦
+-1¦-1¦\(*b\)¦ac¦
+1¦6¦A\(**9\)=¦A***9=79¦
+# GA113(1)
+1¦3¦\(^*ab\)¦*ab¦
+-1¦-1¦\(^*ab\)¦^*ab¦
+-1¦-1¦\(^*b\)¦a*b¦
+-1¦-1¦\(^*b\)¦^*b¦
+### GA113(2) GNU regex implements GA113(1)
+##-1¦-1¦\(^*ab\)¦*ab¦
+##-1¦-1¦\(^*ab\)¦^*ab¦
+##1¦1¦\(^*b\)¦b¦
+##1¦3¦\(^*b\)¦^^b¦
+# GA114
+1¦3¦a^b¦a^b¦
+1¦3¦a\^b¦a^b¦
+1¦1¦^^¦^bc¦
+2¦2¦\^¦a^c¦
+1¦1¦[c^b]¦^abc¦
+1¦1¦[\^ab]¦^ab¦
+2¦2¦[\^ab]¦c\d¦
+-1¦-1¦[^^]¦^¦
+1¦3¦\(a^b\)¦a^b¦
+1¦3¦\(a\^b\)¦a^b¦
+2¦2¦\(\^\)¦a^b¦
+# GA115
+3¦3¦$$¦ab$¦
+-1¦-1¦$$¦$ab¦
+2¦3¦$c¦a$c¦
+2¦2¦[$]¦a$c¦
+1¦2¦\$a¦$a¦
+3¦3¦\$$¦ab$¦
+2¦6¦A\([34]$[34]\)B¦XA4$3BY¦
+# 2.8.3.1.3 Periods in BREs
+# GA116
+1¦1¦.¦abc¦
+-1¦-1¦.ab¦abc¦
+1¦3¦ab.¦abc¦
+1¦3¦a.b¦a,b¦
+-1¦-1¦.......¦PqRs6¦
+1¦7¦.......¦PqRs6T8¦
+# 2.8.3.2 RE Bracket Expression
+# GA118
+2¦2¦[abc]¦xbyz¦
+-1¦-1¦[abc]¦xyz¦
+2¦2¦[abc]¦xbay¦
+# GA119
+2¦2¦[^a]¦abc¦
+4¦4¦[^]cd]¦cd]ef¦
+2¦2¦[^abc]¦axyz¦
+-1¦-1¦[^abc]¦abc¦
+3¦3¦[^[.a.]b]¦abc¦
+3¦3¦[^[=a=]b]¦abc¦
+2¦2¦[^-ac]¦abcde-¦
+2¦2¦[^ac-]¦abcde-¦
+3¦3¦[^a-b]¦abcde¦
+3¦3¦[^a-bd-e]¦dec¦
+2¦2¦[^---]¦-ab¦
+16¦16¦[^a-zA-Z0-9]¦pqrstVWXYZ23579#¦
+# GA120(1)
+3¦3¦[]a]¦cd]ef¦
+1¦1¦[]-a]¦a_b¦
+3¦3¦[][.-.]-0]¦ab0-]¦
+1¦1¦[]^a-z]¦string¦
+# GA120(2)
+4¦4¦[^]cd]¦cd]ef¦
+0¦0¦[^]]*¦]]]]]]]]X¦
+0¦0¦[^]]*¦]]]]]]]]¦
+9¦9¦[^]]\{1,\}¦]]]]]]]]X¦
+-1¦-1¦[^]]\{1,\}¦]]]]]]]]¦
+# GA120(3)
+3¦3¦[c[.].]d]¦ab]cd¦
+2¦8¦[a-z]*[[.].]][A-Z]*¦Abcd]DEFg¦
+# GA121
+2¦2¦[[.a.]b]¦Abc¦
+1¦1¦[[.a.]b]¦aBc¦
+-1¦-1¦[[.a.]b]¦ABc¦
+3¦3¦[^[.a.]b]¦abc¦
+3¦3¦[][.-.]-0]¦ab0-]¦
+3¦3¦[A-[.].]c]¦ab]!¦
+# GA122
+-2¦-2¦[[.ch.]]¦abc¦
+-2¦-2¦[[.ab.][.CD.][.EF.]]¦yZabCDEFQ9¦
+# GA125
+2¦2¦[[=a=]b]¦Abc¦
+1¦1¦[[=a=]b]¦aBc¦
+-1¦-1¦[[=a=]b]¦ABc¦
+3¦3¦[^[=a=]b]¦abc¦
+# GA126
+#W the expected result for [[:alnum:]]* is 2-7 which is wrong
+0¦0¦[[:alnum:]]*¦ aB28gH¦
+2¦7¦[[:alnum:]][[:alnum:]]*¦ aB28gH¦
+#W the expected result for [^[:alnum:]]* is 2-5 which is wrong
+0¦0¦[^[:alnum:]]*¦2 ,a¦
+2¦5¦[^[:alnum:]][^[:alnum:]]*¦2 ,a¦
+#W the expected result for [[:alpha:]]* is 2-5 which is wrong
+0¦0¦[[:alpha:]]*¦ aBgH2¦
+2¦5¦[[:alpha:]][[:alpha:]]*¦ aBgH2¦
+1¦6¦[^[:alpha:]]*¦2 8,a¦
+1¦2¦[[:blank:]]*¦ ¦
+1¦8¦[^[:blank:]]*¦aB28gH, ¦
+1¦2¦[[:cntrl:]]*¦  ¦
+1¦8¦[^[:cntrl:]]*¦aB2 8gh,¦
+#W the expected result for [[:digit:]]* is 2-3 which is wrong
+0¦0¦[[:digit:]]*¦a28¦
+2¦3¦[[:digit:]][[:digit:]]*¦a28¦
+1¦8¦[^[:digit:]]*¦aB gH,¦
+1¦7¦[[:graph:]]*¦aB28gH, ¦
+1¦3¦[^[:graph:]]*¦ ,¦
+1¦2¦[[:lower:]]*¦agB¦
+1¦8¦[^[:lower:]]*¦B2 8H,a¦
+1¦8¦[[:print:]]*¦aB2 8gH, ¦
+1¦2¦[^[:print:]]*¦  ¦
+#W the expected result for [[:punct:]]* is 2-2 which is wrong
+0¦0¦[[:punct:]]*¦a,2¦
+2¦3¦[[:punct:]][[:punct:]]*¦a,,2¦
+1¦9¦[^[:punct:]]*¦aB2 8gH¦
+1¦3¦[[:space:]]*¦ ¦
+#W the expected result for [^[:space:]]* is 2-9 which is wrong
+0¦0¦[^[:space:]]*¦ aB28gH, ¦
+2¦9¦[^[:space:]][^[:space:]]*¦ aB28gH, ¦
+#W the expected result for [[:upper:]]* is 2-3 which is wrong
+0¦0¦[[:upper:]]*¦aBH2¦
+2¦3¦[[:upper:]][[:upper:]]*¦aBH2¦
+1¦8¦[^[:upper:]]*¦a2 8g,B¦
+#W the expected result for [[:xdigit:]]* is 2-5 which is wrong
+0¦0¦[[:xdigit:]]*¦gaB28h¦
+2¦5¦[[:xdigit:]][[:xdigit:]]*¦gaB28h¦
+#W the expected result for [^[:xdigit:]]* is 2-7 which is wrong
+2¦7¦[^[:xdigit:]][^[:xdigit:]]*¦a gH,2¦
+# GA127
+-2¦-2¦[b-a]¦abc¦
+1¦1¦[a-c]¦bbccde¦
+2¦2¦[a-b]¦-bc¦
+3¦3¦[a-z0-9]¦AB0¦
+3¦3¦[^a-b]¦abcde¦
+3¦3¦[^a-bd-e]¦dec¦
+1¦1¦[]-a]¦a_b¦
+2¦2¦[+--]¦a,b¦
+2¦2¦[--/]¦a.b¦
+2¦2¦[^---]¦-ab¦
+3¦3¦[][.-.]-0]¦ab0-]¦
+3¦3¦[A-[.].]c]¦ab]!¦
+2¦6¦bc[d-w]xy¦abchxyz¦
+# GA129
+1¦1¦[a-cd-f]¦dbccde¦
+-1¦-1¦[a-ce-f]¦dBCCdE¦
+2¦4¦b[n-zA-M]Y¦absY9Z¦
+2¦4¦b[n-zA-M]Y¦abGY9Z¦
+# GA130
+3¦3¦[-xy]¦ac-¦
+2¦4¦c[-xy]D¦ac-D+¦
+2¦2¦[--/]¦a.b¦
+2¦4¦c[--/]D¦ac.D+b¦
+2¦2¦[^-ac]¦abcde-¦
+1¦3¦a[^-ac]c¦abcde-¦
+3¦3¦[xy-]¦zc-¦
+2¦4¦c[xy-]7¦zc-786¦
+2¦2¦[^ac-]¦abcde-¦
+2¦4¦a[^ac-]c¦5abcde-¦
+2¦2¦[+--]¦a,b¦
+2¦4¦a[+--]B¦Xa,By¦
+2¦2¦[^---]¦-ab¦
+4¦6¦X[^---]Y¦X-YXaYXbY¦
+# 2.8.3.3 BREs Matching Multiple Characters
+# GA131
+3¦4¦cd¦abcdeabcde¦
+1¦2¦ag*b¦abcde¦
+-1¦-1¦[a-c][e-f]¦abcdef¦
+3¦4¦[a-c][e-f]¦acbedf¦
+4¦8¦abc*XYZ¦890abXYZ#*¦
+4¦9¦abc*XYZ¦890abcXYZ#*¦
+4¦15¦abc*XYZ¦890abcccccccXYZ#*¦
+-1¦-1¦abc*XYZ¦890abc*XYZ#*¦
+# GA132
+2¦4¦\(*bc\)¦a*bc¦
+1¦2¦\(ab\)¦abcde¦
+1¦10¦\(a\(b\(c\(d\(e\(f\(g\)h\(i\(j\)\)\)\)\)\)\)\)¦abcdefghijk¦
+3¦8¦43\(2\(6\)*0\)AB¦654320ABCD¦
+3¦9¦43\(2\(7\)*0\)AB¦6543270ABCD¦
+3¦12¦43\(2\(7\)*0\)AB¦6543277770ABCD¦
+# GA133
+1¦10¦\(a\(b\(c\(d\(e\(f\(g\)h\(i\(j\)\)\)\)\)\)\)\)¦abcdefghijk¦
+-1¦-1¦\(a\(b\(c\(d\(e\(f\(g\)h\(i\(k\)\)\)\)\)\)\)\)¦abcdefghijk¦
+# GA134
+2¦4¦\(bb*\)¦abbbc¦
+2¦2¦\(bb*\)¦ababbbc¦
+1¦6¦a\(.*b\)¦ababbbc¦
+1¦2¦a\(b*\)¦ababbbc¦
+1¦20¦a\(.*b\)c¦axcaxbbbcsxbbbbbbbbc¦
+# GA135
+1¦7¦\(a\(b\(c\(d\(e\)\)\)\)\)\4¦abcdededede¦
+#W POSIX does not really specify whether a\(b\)*c\1 matches acb.
+#W back references are supposed to expand to the last match, but what
+#W if there never was a match as in this case?
+-1¦-1¦a\(b\)*c\1¦acb¦
+1¦11¦\(a\(b\(c\(d\(e\(f\(g\)h\(i\(j\)\)\)\)\)\)\)\)\9¦abcdefghijjk¦
+# GA136
+#W These two tests have the same problem as the test in GA135. No match
+#W of a subexpression, why should the back reference be usable?
+#W 1 2 a\(b\)*c\1 acb
+#W 4 7 a\(b\(c\(d\(f\)*\)\)\)\4¦xYzabcdePQRST
+-1¦-1¦a\(b\)*c\1¦acb¦
+-1¦-1¦a\(b\(c\(d\(f\)*\)\)\)\4¦xYzabcdePQRST¦
+# GA137
+-2¦-2¦\(a\(b\)\)\3¦foo¦
+-2¦-2¦\(a\(b\)\)\(a\(b\)\)\5¦foo¦
+# GA138
+1¦2¦ag*b¦abcde¦
+1¦10¦a.*b¦abababvbabc¦
+2¦5¦b*c¦abbbcdeabbbbbbcde¦
+2¦5¦bbb*c¦abbbcdeabbbbbbcde¦
+1¦5¦a\(b\)*c\1¦abbcbbb¦
+-1¦-1¦a\(b\)*c\1¦abbdbd¦
+0¦0¦\([a-c]*\)\1¦abcacdef¦
+1¦6¦\([a-c]*\)\1¦abcabcabcd¦
+1¦2¦a^*b¦ab¦
+1¦5¦a^*b¦a^^^b¦
+# GA139
+1¦2¦a\{2\}¦aaaa¦
+1¦7¦\([a-c]*\)\{0,\}¦aabcaab¦
+1¦2¦\(a\)\1\{1,2\}¦aabc¦
+1¦3¦\(a\)\1\{1,2\}¦aaaabc¦
+#W the expression \(\(a\)\1\)\{1,2\} is ill-formed, using \2
+1¦4¦\(\(a\)\2\)\{1,2\}¦aaaabc¦
+# GA140
+1¦2¦a\{2\}¦aaaa¦
+-1¦-1¦a\{2\}¦abcd¦
+0¦0¦a\{0\}¦aaaa¦
+1¦64¦a\{64\}¦aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¦
+# GA141
+1¦7¦\([a-c]*\)\{0,\}¦aabcaab¦
+#W the expected result for \([a-c]*\)\{2,\} is failure which isn't correct
+1¦3¦\([a-c]*\)\{2,\}¦abcdefg¦
+1¦3¦\([a-c]*\)\{1,\}¦abcdefg¦
+-1¦-1¦a\{64,\}¦aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¦
+# GA142
+1¦3¦a\{2,3\}¦aaaa¦
+-1¦-1¦a\{2,3\}¦abcd¦
+0¦0¦\([a-c]*\)\{0,0\}¦foo¦
+1¦63¦a\{1,63\}¦aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¦
+# 2.8.3.4 BRE Precedence
+# GA143
+#W There are numerous bugs in the original version.
+2¦19¦\^\[[[.].]]\\(\\1\\)\*\\{1,2\\}\$¦a^[]\(\1\)*\{1,2\}$b¦
+1¦6¦[[=*=]][[=\=]][[=]=]][[===]][[...]][[:punct:]]¦*\]=.;¦
+1¦6¦[$\(*\)^]*¦$\()*^¦
+1¦1¦[\1]¦1¦
+1¦1¦[\{1,2\}]¦{¦
+#W the expected result for \(*\)*\1* is 2-2 which isn't correct
+0¦0¦\(*\)*\1*¦a*b*11¦
+2¦3¦\(*\)*\1*b¦a*b*11¦
+#W the expected result for \(a\(b\{1,2\}\)\{1,2\}\) is 1-5 which isn't correct
+1¦3¦\(a\(b\{1,2\}\)\{1,2\}\)¦abbab¦
+1¦5¦\(a\(b\{1,2\}\)\)\{1,2\}¦abbab¦
+1¦1¦^\(^\(^a$\)$\)$¦a¦
+1¦2¦\(a\)\1$¦aa¦
+1¦3¦ab*¦abb¦
+1¦4¦ab\{2,4\}¦abbbc¦
+# 2.8.3.5 BRE Expression Anchoring
+# GA144
+1¦1¦^a¦abc¦
+-1¦-1¦^b¦abc¦
+-1¦-1¦^[a-zA-Z]¦99Nine¦
+1¦4¦^[a-zA-Z]*¦Nine99¦
+# GA145(1)
+1¦2¦\(^a\)\1¦aabc¦
+-1¦-1¦\(^a\)\1¦^a^abc¦
+1¦2¦\(^^a\)¦^a¦
+1¦1¦\(^^\)¦^^¦
+1¦3¦\(^abc\)¦abcdef¦
+-1¦-1¦\(^def\)¦abcdef¦
+### GA145(2) GNU regex implements GA145(1)
+##-1¦-1¦\(^a\)\1¦aabc¦
+##1¦4¦\(^a\)\1¦^a^abc¦
+##-1¦-1¦\(^^a\)¦^a¦
+##1¦2¦\(^^\)¦^^¦
+# GA146
+3¦3¦a$¦cba¦
+-1¦-1¦a$¦abc¦
+5¦7¦[a-z]*$¦99ZZxyz¦
+#W the expected result for [a-z]*$ is failure which isn't correct
+10¦9¦[a-z]*$¦99ZZxyz99¦
+3¦3¦$$¦ab$¦
+-1¦-1¦$$¦$ab¦
+3¦3¦\$$¦ab$¦
+# GA147(1)
+-1¦-1¦\(a$\)\1¦bcaa¦
+-1¦-1¦\(a$\)\1¦ba$¦
+-1¦-1¦\(ab$\)¦ab$¦
+1¦2¦\(ab$\)¦ab¦
+4¦6¦\(def$\)¦abcdef¦
+-1¦-1¦\(abc$\)¦abcdef¦
+### GA147(2) GNU regex implements GA147(1)
+##-1¦-1¦\(a$\)\1¦bcaa¦
+##2¦5¦\(a$\)\1¦ba$a$¦
+##-1¦-1¦\(ab$\)¦ab¦
+##1¦3¦\(ab$\)¦ab$¦
+# GA148
+0¦0¦^$¦¦
+1¦3¦^abc$¦abc¦
+-1¦-1¦^xyz$¦^xyz^¦
+-1¦-1¦^234$¦^234$¦
+1¦9¦^[a-zA-Z0-9]*$¦2aA3bB9zZ¦
+-1¦-1¦^[a-z0-9]*$¦2aA3b#B9zZ¦
diff --git a/libc/posix/PTESTS2C.sed b/libc/posix/PTESTS2C.sed
new file mode 100644
index 000000000..b6850a375
--- /dev/null
+++ b/libc/posix/PTESTS2C.sed
@@ -0,0 +1,6 @@
+/^##/d
+s/^# \(.*\)/ { 0, 0, "\1", NULL, },/
+s/^#W \(.*\)/ { 0, 0, NULL, "\1" },/
+s/\([^¦]*\)¦\([^¦]*\)¦\([^¦]*\)¦\([^¦]*\)¦\(.*\)/ { \1, \2, "\3", "\4", \5 },/
+s/\\/\\\\/g
+s/ /\\r/g
diff --git a/libc/posix/TESTS b/libc/posix/TESTS
new file mode 100644
index 000000000..f2c988640
--- /dev/null
+++ b/libc/posix/TESTS
@@ -0,0 +1,167 @@
+0:(.*)*\1:xx
+0:^:
+0:$:
+0:^$:
+0:^a$:a
+0:abc:abc
+1:abc:xbc
+1:abc:axc
+1:abc:abx
+0:abc:xabcy
+0:abc:ababc
+0:ab*c:abc
+0:ab*bc:abc
+0:ab*bc:abbc
+0:ab*bc:abbbbc
+0:ab+bc:abbc
+1:ab+bc:abc
+1:ab+bc:abq
+0:ab+bc:abbbbc
+0:ab?bc:abbc
+0:ab?bc:abc
+1:ab?bc:abbbbc
+0:ab?c:abc
+0:^abc$:abc
+1:^abc$:abcc
+0:^abc:abcc
+1:^abc$:aabc
+0:abc$:aabc
+0:^:abc
+0:$:abc
+0:a.c:abc
+0:a.c:axc
+0:a.*c:axyzc
+1:a.*c:axyzd
+1:a[bc]d:abc
+0:a[bc]d:abd
+1:a[b-d]e:abd
+0:a[b-d]e:ace
+0:a[b-d]:aac
+0:a[-b]:a-
+0:a[b-]:a-
+2:a[b-a]:-
+2:a[]b:-
+2:a[:-
+0:a]:a]
+0:a[]]b:a]b
+0:a[^bc]d:aed
+1:a[^bc]d:abd
+0:a[^-b]c:adc
+1:a[^-b]c:a-c
+1:a[^]b]c:a]c
+0:a[^]b]c:adc
+0:ab|cd:abc
+0:ab|cd:abcd
+0:()ef:def
+0:()*:-
+2:*a:-
+2:^*:-
+2:$*:-
+2:(*)b:-
+1:$b:b
+2:a\:-
+0:a\(b:a(b
+0:a\(*b:ab
+0:a\(*b:a((b
+1:a\x:a\x
+1:abc):-
+2:(abc:-
+0:((a)):abc
+0:(a)b(c):abc
+0:a+b+c:aabbabc
+0:a**:-
+0:a*?:-
+0:(a*)*:-
+0:(a*)+:-
+0:(a|)*:-
+0:(a*|b)*:-
+0:(a+|b)*:ab
+0:(a+|b)+:ab
+0:(a+|b)?:ab
+0:[^ab]*:cde
+0:(^)*:-
+0:(ab|)*:-
+2:)(:-
+1:abc:
+1:abc:
+0:a*:
+0:([abc])*d:abbbcd
+0:([abc])*bcd:abcd
+0:a|b|c|d|e:e
+0:(a|b|c|d|e)f:ef
+0:((a*|b))*:-
+0:abcd*efg:abcdefg
+0:ab*:xabyabbbz
+0:ab*:xayabbbz
+0:(ab|cd)e:abcde
+0:[abhgefdc]ij:hij
+1:^(ab|cd)e:abcde
+0:(abc|)ef:abcdef
+0:(a|b)c*d:abcd
+0:(ab|ab*)bc:abc
+0:a([bc]*)c*:abc
+0:a([bc]*)(c*d):abcd
+0:a([bc]+)(c*d):abcd
+0:a([bc]*)(c+d):abcd
+0:a[bcd]*dcdcde:adcdcde
+1:a[bcd]+dcdcde:adcdcde
+0:(ab|a)b*c:abc
+0:((a)(b)c)(d):abcd
+0:[A-Za-z_][A-Za-z0-9_]*:alpha
+0:^a(bc+|b[eh])g|.h$:abh
+0:(bc+d$|ef*g.|h?i(j|k)):effgz
+0:(bc+d$|ef*g.|h?i(j|k)):ij
+1:(bc+d$|ef*g.|h?i(j|k)):effg
+1:(bc+d$|ef*g.|h?i(j|k)):bcdd
+0:(bc+d$|ef*g.|h?i(j|k)):reffgz
+1:((((((((((a)))))))))):-
+0:(((((((((a))))))))):a
+1:multiple words of text:uh-uh
+0:multiple words:multiple words, yeah
+0:(.*)c(.*):abcde
+1:\((.*),:(.*)\)
+1:[k]:ab
+0:abcd:abcd
+0:a(bc)d:abcd
+0:a[-]?c:ac
+0:(....).*\1:beriberi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Qaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mo'ammar Gadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Kaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Qadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moammar El Kadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Gadafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar al-Qadafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moamer El Kazzafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moamar al-Gaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar Al Qathafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Al Qathafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mo'ammar el-Gadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moamar El Kadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar al-Qadhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar al-Qadhdhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar Qadafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moamar Gaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar Qadhdhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Khaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar al-Khaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'amar al-Kadafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Ghaddafy
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Ghadafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Ghaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muamar Kaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Quathafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muammar Gheddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Muamar Al-Kaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moammar Khadafy
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Moammar Qudhafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mu'ammar al-Qaddafi
+0:M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]:Mulazim Awwal Mu'ammar Muhammad Abu Minyar al-Qadhafi
+0:[[:digit:]]+:01234
+1:[[:alpha:]]+:01234
+0:^[[:digit:]]*$:01234
+1:^[[:digit:]]*$:01234a
+0:^[[:alnum:]]*$:01234a
+0:^[[:xdigit:]]*$:01234a
+1:^[[:xdigit:]]*$:01234g
+0:^[[:alnum:][:space:]]*$:Hello world
diff --git a/libc/posix/TESTS2C.sed b/libc/posix/TESTS2C.sed
new file mode 100644
index 000000000..d8c2d7261
--- /dev/null
+++ b/libc/posix/TESTS2C.sed
@@ -0,0 +1,2 @@
+s/\\/\\\\/g
+s/\([0-9]*\):\(.*\):\(.*\)/ {\1, "\2", "\3"},/
diff --git a/libc/posix/Versions b/libc/posix/Versions
new file mode 100644
index 000000000..f529ee9d8
--- /dev/null
+++ b/libc/posix/Versions
@@ -0,0 +1,128 @@
+libc {
+ GLIBC_2.0 {
+ # functions with special/multiple interfaces
+ __bsd_getpgrp; __setpgid; __getpgid;
+
+ # functions with required interface outside normal name space
+ _exit;
+
+ # functions used in other libraries
+ __sched_get_priority_max; __sched_get_priority_min;
+ __sched_getparam; __sched_getscheduler; __sched_setscheduler;
+ __sched_yield; __fork; __getpid; __wait;
+
+ # functions used by libstdc++ 2.7.2
+ __waitpid;
+
+ # global variables
+ __environ; _environ;
+
+ # variables in normal name space
+ environ; optarg; opterr; optind; optopt;
+ re_max_failures; re_syntax_options;
+
+ # a*
+ alarm;
+
+ # c*
+ confstr;
+
+ # e*
+ execl; execle; execlp; execv; execve; execvp; fexecve;
+
+ # f*
+ fnmatch; fork; fpathconf; freeaddrinfo;
+
+ # g*
+ getaddrinfo; getdtablesize; getegid; geteuid; getgid; getopt; getopt_long;
+ getopt_long_only; getpgid; getpgrp; getpid; getppid; getsid; getuid; glob;
+ glob_pattern_p; globfree; group_member;
+
+ # n*
+ nanosleep;
+
+ # p*
+ pathconf; pause; pselect;
+
+ # r*
+ re_comp; re_compile_fastmap; re_compile_pattern; re_exec; re_match;
+ re_match_2; re_search; re_search_2; re_set_registers; re_set_syntax;
+ regcomp; regerror; regexec; regfree;
+
+ # s*
+ sched_get_priority_max; sched_get_priority_min; sched_getparam;
+ sched_getscheduler; sched_rr_get_interval; sched_setparam;
+ sched_setscheduler; sched_yield; setegid; seteuid; setgid; setlogin;
+ setpgid; setpgrp; setsid; setuid; sleep; sysconf;
+
+ # t*
+ times;
+
+ # u*
+ uname;
+
+ # v*
+ vfork;
+
+ # w*
+ wait; wait3; wait4; waitpid;
+ }
+ GLIBC_2.1 {
+ # functions used in other libraries
+ __pread64; __pwrite64;
+
+ # g*
+ gai_strerror; getnameinfo; glob64; globfree64;
+
+ # p*
+ pread; pread64; pwrite; pwrite64;
+
+ # w*
+ waitid; wordexp; wordfree;
+ }
+ GLIBC_2.1.2 {
+ # functions used in other libraries
+ __vfork;
+ }
+ GLIBC_2.2 {
+ # p*
+ posix_spawn_file_actions_init; posix_spawn_file_actions_destroy;
+ posix_spawn_file_actions_addclose; posix_spawn_file_actions_addopen;
+ posix_spawn_file_actions_adddup2;
+ posix_spawnattr_init; posix_spawnattr_destroy;
+ posix_spawnattr_getsigdefault; posix_spawnattr_setsigdefault;
+ posix_spawnattr_getflags; posix_spawnattr_setflags;
+ posix_spawnattr_getpgroup; posix_spawnattr_setpgroup;
+ posix_spawnattr_setsigmask; posix_spawnattr_getsigmask;
+ posix_spawn; posix_spawnp; posix_spawnattr_getschedpolicy;
+ posix_spawnattr_setschedpolicy; posix_spawnattr_getschedparam;
+ posix_spawnattr_setschedparam;
+
+ # Used in macros.
+ __sysconf;
+ }
+ GLIBC_2.2.3 {
+ # Extended Interface.
+ fnmatch;
+ }
+ GLIBC_2.2.6 {
+ # For syscall wrapper
+ __nanosleep;
+ }
+ GLIBC_2.3.2 {
+ # Note that these symbols appear in sysdeps/unix/sysv/linux/Versions
+ # under GLIBC_2.0; the first instance in the script is taken as the
+ # default, so linux configurations put them in GLIBC_2.0 while other
+ # configuration put them in GLIBC_2.3.2.
+ getresuid; getresgid; setresuid; setresgid;
+ }
+ GLIBC_2.3.3 {
+ sched_getaffinity; sched_setaffinity;
+ }
+ GLIBC_2.3.4 {
+ regexec;
+ }
+ GLIBC_PRIVATE {
+ __libc_fork; __libc_pwrite;
+ }
+}
diff --git a/libc/posix/_exit.c b/libc/posix/_exit.c
new file mode 100644
index 000000000..673667df3
--- /dev/null
+++ b/libc/posix/_exit.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991,94,95,96,97,99,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+
+/* The function `_exit' should take a status argument and simply
+ terminate program execution, using the low-order 8 bits of the
+ given integer as status. */
+void
+_exit (status)
+ int status;
+{
+ status &= 0xff;
+ abort ();
+}
+libc_hidden_def (_exit)
+weak_alias (_exit, _Exit)
+
+stub_warning (_exit)
+#include <stub-tag.h>
diff --git a/libc/posix/alarm.c b/libc/posix/alarm.c
new file mode 100644
index 000000000..1f0cceb58
--- /dev/null
+++ b/libc/posix/alarm.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1991,95,96,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM.
+ If SECONDS is zero, any currently scheduled alarm will be cancelled.
+ The function returns the number of seconds remaining until the last
+ alarm scheduled would have signaled, or zero if there wasn't one.
+ There is no return value to indicate an error, but you can set `errno'
+ to 0 and check its value after calling `alarm', and this might tell you.
+ The signal may come late due to processor scheduling. */
+unsigned int
+alarm (seconds)
+ unsigned int seconds;
+{
+ __set_errno (ENOSYS);
+ return 0;
+}
+libc_hidden_def (alarm)
+
+stub_warning (alarm)
+#include <stub-tag.h>
diff --git a/libc/posix/annexc.c b/libc/posix/annexc.c
new file mode 100644
index 000000000..df5913aed
--- /dev/null
+++ b/libc/posix/annexc.c
@@ -0,0 +1,890 @@
+/* Copyright (C) 1998, 2000, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <ctype.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#define HEADER_MAX 256
+
+static const char *macrofile;
+
+/* <aio.h>. */
+static const char *const aio_syms[] =
+{
+ "AIO_ALLDONE", "AIO_CANCELED", "AIO_NOTCANCELED", "LIO_NOP", "LIO_NOWAIT",
+ "LIO_READ", "LIO_WAIT", "LIO_WRITE",
+ /* From <fcntl.h>. */
+ "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
+ "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
+ "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
+ "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
+ "O_WRONLY",
+ /* From <signal.h>. */
+ "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
+ "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_SIGNAL", "SIGEV_THREAD",
+ "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
+ "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
+ "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
+ "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
+ "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
+};
+static const char *const aio_maybe[] =
+{
+ "aio_cancel", "aio_error", "aio_fsync", "aio_read", "aio_return",
+ "aio_suspend", "aio_write", "lio_listio",
+ /* From <fcntl.h>. */
+ "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
+ "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
+ "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
+ "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR",
+ /* From <signal.h>. */
+ "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
+ "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
+ "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
+};
+
+/* <assert.h>. */
+static const char *const assert_syms[] =
+{
+ "assert"
+};
+static const char *const assert_maybe[] =
+{
+};
+
+/* <ctype.h>. */
+static const char *const ctype_syms[] =
+{
+};
+static const char *const ctype_maybe[] =
+{
+ "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
+ "isprint", "ispunct", "isspace", "isupper", "isxdigit", "tolower",
+ "toupper"
+};
+
+/* <dirent.h>. */
+static const char *const dirent_syms[] =
+{
+};
+static const char *const dirent_maybe[] =
+{
+ "closedir", "opendir", "readdir", "readdir_r", "rewinddir"
+};
+
+/* <errno.h>. */
+static const char *const errno_syms[] =
+{
+ "E2BIG", "EACCES", "EAGAIN", "EBADF", "EBADMSG", "EBUSY", "ECANCELED",
+ "ECHILD", "EDEADLK", "EDOM", "EEXIST", "EFAULT", "EFBIG", "EINPROGRESS",
+ "EINTR", "EINVAL", "EIO", "EISDIR", "EMFILE", "EMLINK", "EMSGSIZE",
+ "ENAMETOOLONG", "ENFILE", "ENODEV", "ENOENT", "ENOEXEC", "ENOLCK",
+ "ENOMEM", "ENOSPC", "ENOSYS", "ENOTDIR", "ENOTEMPTY", "ENOTSUP",
+ "ENOTTY", "ENXIO", "EPERM", "EPIPE", "ERANGE", "EROFS", "ESPIPE",
+ "ESRCH", "ETIMEDOUT", "EXDEV"
+};
+static const char *const errno_maybe[] =
+{
+ "errno", "E*"
+};
+
+/* <fcntl.h>. */
+static const char *const fcntl_syms[] =
+{
+ "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
+ "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
+ "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
+ "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
+ "O_WRONLY"
+};
+static const char *const fcntl_maybe[] =
+{
+ "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
+ "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
+ "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
+ "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR"
+};
+
+/* <float.h>. */
+static const char *const float_syms[] =
+{
+ "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX", "DBL_MAX_10_EXP",
+ "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP", "DBL_MIN_EXP", "FLT_DIG",
+ "FLT_EPSILON", "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
+ "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX", "FLT_ROUNDS",
+ "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX", "LDBL_MAX_10_EXP",
+ "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP", "LDBL_MIN_EXP"
+};
+static const char *const float_maybe[] =
+{
+};
+
+/* <grp.h>. */
+static const char *const grp_syms[] =
+{
+};
+static const char *const grp_maybe[] =
+{
+ "getgrgid", "getgrgid_r", "getgrnam", "getgrnam_r"
+};
+
+/* <limits.h>. */
+static const char *const limits_syms[] =
+{
+ "_POSIX_AIO_LISTIO_MAX", "_POSIX_AIO_MAX", "_POSIX_ARG_MAX",
+ "_POSIX_CHILD_MAX", "_POSIX_CLOCKRES_MAX", "_POSIX_DELAYTIMER_MAX",
+ "_POSIX_LINK_MAX", "_POSIX_LOGIN_NAME_MAX", "_POSIX_MAX_CANON",
+ "_POSIX_MAX_INPUT", "_POSIX_MQ_OPEN_MAX", "_POSIX_MQ_PRIO_MAX",
+ "_POSIX_NAME_MAX", "_POSIX_NGROUPS_MAX", "_POSIX_OPEN_MAX",
+ "_POSIX_PATH_MAX", "_POSIX_PIPE_BUF", "_POSIX_RTSIG_MAX",
+ "_POSIX_SEM_NSEMS_MAX", "_POSIX_SEM_VALUE_MAX", "_POSIX_SIGQUEUE_MAX",
+ "_POSIX_SSIZE_MAX", "_POSIX_STREAM_MAX",
+ "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", "_POSIX_THREAD_KEYS_MAX",
+ "_POSIX_THREAD_THREADS_MAX", "_POSIX_TIMER_MAX", "_POSIX_TTY_NAME_MAX",
+ "_POSIX_TZNAME_MAX", "_POSIX_THREAD_DESTRUCTOR_ITERATIONS",
+ "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "INT_MAX", "INT_MIN", "LONG_MAX",
+ "LONG_MIN", "MB_LEN_MAX", "NGROUPS_MAX", "PAGESIZE", "SCHAR_MAX",
+ "SCHAR_MIN", "SHRT_MAX", "SHRT_MIN", "UCHAR_MAX", "UINT_MAX",
+ "ULONG_MAX", "USHRT_MAX"
+};
+static const char *const limits_maybe[] =
+{
+ "AIO_LISTIO_MAX", "AIO_MAX", "ARG_MAX", "CHILD_MAX", "DELAYTIMER_MAX",
+ "LINK_MAX", "LOGIN_NAME_MAX", "LONG_MAX", "LONG_MIN", "MAX_CANON",
+ "MAX_INPUT", "MQ_OPEN_MAX", "MQ_PRIO_MAX", "NAME_MAX", "OPEN_MAX",
+ "PATH_MAX", "PIPE_BUF", "RTSIG_MAX", "PTHREAD_DESTRUCTOR_ITERATIONS",
+ "PTHREAD_KEYS_MAX", "PTHREAD_STACK_MIN", "PTHREAD_THREADS_MAX"
+};
+
+/* <locale.h>. */
+static const char *const locale_syms[] =
+{
+ "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
+ "LC_TIME", "NULL"
+};
+static const char *const locale_maybe[] =
+{
+ "LC_*", "localeconv", "setlocale"
+};
+
+/* <math.h>. */
+static const char *const math_syms[] =
+{
+ "HUGE_VAL"
+};
+static const char *const math_maybe[] =
+{
+ "acos", "asin", "atan2", "atan", "ceil", "cos", "cosh", "exp",
+ "fabs", "floor", "fmod", "frexp", "ldexp", "log10", "log", "modf",
+ "pow", "sin", "sinh", "sqrt", "tan", "tanh",
+ "acosf", "asinf", "atan2f", "atanf", "ceilf", "cosf", "coshf", "expf",
+ "fabsf", "floorf", "fmodf", "frexpf", "ldexpf", "log10f", "logf", "modff",
+ "powf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf",
+ "acosl", "asinl", "atan2l", "atanl", "ceill", "cosl", "coshl", "expl",
+ "fabsl", "floorl", "fmodl", "frexpl", "ldexpl", "log10l", "logl", "modfl",
+ "powl", "sinl", "sinhl", "sqrtl", "tanl", "tanhl"
+};
+
+/* <mqueue.h>. */
+static const char *const mqueue_syms[] =
+{
+};
+static const char *const mqueue_maybe[] =
+{
+ "mq_close", "mq_getattr", "mq_notify", "mq_open", "mq_receive",
+ "mq_send", "mq_setattr", "mq_unlink"
+};
+
+/* <pthread.h>. */
+static const char *const pthread_syms[] =
+{
+ "PTHREAD_CANCELED", "PTHREAD_CANCEL_ASYNCHRONOUS",
+ "PTHREAD_CANCEL_DEFERRED", "PTHREAD_CANCEL_DISABLE", "PTHREAD_CANCEL_ENABLE",
+ "PTHREAD_COND_INITIALIZER", "PTHREAD_CREATE_DETACHED",
+ "PTHREAD_CREATE_JOINABLE", "PTHREAD_EXPLICIT_SCHED",
+ "PTHREAD_INHERIT_SCHED", "PTHREAD_MUTEX_INITIALIZER",
+ "PTHREAD_ONCE_INIT", "PTHREAD_PRIO_INHERIT", "PTHREAD_PRIO_NONE",
+ "PTHREAD_PRIO_PROTECT", "PTHREAD_PROCESS_PRIVATE",
+ "PTHREAD_PROCESS_SHARED", "PTHREAD_SCOPE_PROCESS", "PTHREAD_SCOPE_SYSTEM",
+ /* These come from <sched.h>. */
+ "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
+ /* These come from <time.h>. */
+ "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
+};
+static const char *const pthread_maybe[] =
+{
+ "pthread_atfork", "pthread_attr_destroy", "pthread_attr_getdetachstate",
+ "pthread_attr_getinheritsched", "pthread_attr_getschedparam",
+ "pthread_attr_getschedpolicy", "pthread_attr_getscope",
+ "pthread_attr_getstackaddr", "pthread_attr_getstacksize",
+ "pthread_attr_init", "pthread_attr_setdetachstate",
+ "pthread_attr_setinheritsched", "pthread_attr_setschedparam",
+ "pthread_attr_setschedpolicy", "pthread_attr_setscope",
+ "pthread_attr_setstackaddr", "pthread_attr_setstacksize",
+ "pthread_cleanup_pop", "pthread_cleanup_push", "pthread_cond_broadcast",
+ "pthread_cond_destroy", "pthread_cond_init", "pthread_cond_signal",
+ "pthread_cond_timedwait", "pthread_cond_wait", "pthread_condattr_destroy",
+ "pthread_condattr_getpshared", "pthread_condattr_init",
+ "pthread_condattr_setpshared", "pthread_create", "pthread_detach",
+ "pthread_equal", "pthread_exit", "pthread_getspecific", "pthread_join",
+ "pthread_key_create", "pthread_key_destroy", "pthread_kill",
+ "pthread_mutex_destroy", "pthread_mutex_getprioceiling",
+ "pthread_mutex_init", "pthread_mutex_lock", "pthread_mutex_setprioceiling",
+ "pthread_mutex_trylock", "pthread_mutex_unlock", "pthread_mutexattr_destroy",
+ "pthread_mutexattr_getprioceiling", "pthread_mutexattr_getprotocol",
+ "pthread_mutexattr_getpshared", "pthread_mutexattr_init",
+ "pthread_mutexattr_setprioceiling", "pthread_mutexattr_setprotocol",
+ "pthread_mutexattr_setpshared", "pthread_once", "pthread_self",
+ "pthread_setcancelstate", "pthread_setcanceltype", "pthread_setspecific",
+ "pthread_sigmask", "pthread_testcancel"
+ /* These come from <sched.h>. */
+ "sched_get_priority_max", "sched_get_priority_min",
+ "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
+ "sched_setparam", "sched_setscheduler", "sched_yield",
+ /* These come from <time.h>. */
+ "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
+ "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
+ "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
+ "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
+ "timer_settime", "tzset"
+};
+
+/* <pwd.h>. */
+static const char *const pwd_syms[] =
+{
+};
+static const char *const pwd_maybe[] =
+{
+ "getpwnam", "getpwnam_r", "getpwuid", "getpwuid_r"
+};
+
+/* <sched.h>. */
+static const char *const sched_syms[] =
+{
+ "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
+};
+static const char *const sched_maybe[] =
+{
+ "sched_get_priority_max", "sched_get_priority_min",
+ "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
+ "sched_setparam", "sched_setscheduler", "sched_yield",
+ /* These come from <time.h>. */
+ "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
+ "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
+ "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
+ "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
+ "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
+ "timer_settime", "tzset"
+};
+
+/* <semaphore.h>. */
+static const char *const semaphore_syms[] =
+{
+};
+static const char *const semaphore_maybe[] =
+{
+ "sem_close", "sem_destroy", "sem_getvalue", "sem_init", "sem_open",
+ "sen_post", "sem_trywait", "sem_unlink", "sem_wait"
+};
+
+/* <setjmp.h>. */
+static const char *const setjmp_syms[] =
+{
+};
+static const char *const setjmp_maybe[] =
+{
+ "longjmp", "setjmp", "siglongjmp", "sigsetjmp"
+};
+
+/* <signal.h>. */
+static const char *const signal_syms[] =
+{
+ "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
+ "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_THREAD",
+ "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
+ "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
+ "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
+ "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
+ "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
+};
+static const char *const signal_maybe[] =
+{
+ "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
+ "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
+ "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
+};
+
+/* <stdarg.h>. */
+static const char *const stdarg_syms[] =
+{
+ "va_arg", "va_end", "va_start"
+};
+static const char *const stdarg_maybe[] =
+{
+ "va_list"
+};
+
+/* <stddef.h>. */
+static const char *const stddef_syms[] =
+{
+ "NULL", "offsetof"
+};
+static const char *const stddef_maybe[] =
+{
+};
+
+/* <stdio.h>. */
+static const char *const stdio_syms[] =
+{
+ "BUFSIZ", "EOF", "FILENAME_MAX", "FOPEN_MAX", "L_ctermid", "L_cuserid",
+ "L_tmpnam", "NULL", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STREAM_MAX",
+ "TMP_MAX", "stderr", "stdin", "stdout", "_IOFBF", "_IOLBF", "_IONBF"
+};
+static const char *const stdio_maybe[] =
+{
+ "clearerr", "fclose", "fdopen", "feof", "ferror", "fflush", "fgetc",
+ "fgetpos", "fgets", "fileno", "flockfile", "fopen", "fprintf", "fputc",
+ "fputs", "fread", "freopen", "fscanf", "fseek", "fsetpos", "ftell",
+ "ftrylockfile", "funlockfile", "fwrite", "getc", "getchar",
+ "getchar_unlocked", "getc_unlocked", "gets", "perror", "printf", "putc",
+ "putchar", "putchar_unlocked", "putc_unlocked", "puts", "remove", "rename",
+ "rewind", "scanf", "setbuf", "setvbuf", "sprintf", "sscanf", "tmpfile",
+ "tmpnam", "ungetc", "vfprintf", "vprintf", "vsprintf"
+};
+
+/* <stdlib.h>. */
+static const char *const stdlib_syms[] =
+{
+ "EXIT_FAILURE", "EXIT_SUCCESS", "MB_CUR_MAX", "NULL", "RAND_MAX"
+};
+static const char *const stdlib_maybe[] =
+{
+ "abort", "abs", "atexit", "atof", "atoi", "atol", "bsearch", "calloc",
+ "div", "exit", "free", "getenv", "labs", "ldiv", "malloc", "mblen",
+ "mbstowcs", "mbtowc", "qsort", "rand", "rand_r", "realloc", "srand",
+ "strtod", "strtol", "strtoul", "system", "wcstombs", "wctomb"
+};
+
+/* <string.h>. */
+static const char *const string_syms[] =
+{
+ "NULL"
+};
+static const char *const string_maybe[] =
+{
+ "memchr", "memcmp", "memcpy", "memmove", "memset", "strcat", "strchr",
+ "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen",
+ "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn",
+ "strstr", "strtok", "strtok_r", "strxfrm"
+};
+
+/* <sys/mman.h>. */
+static const char *const mman_syms[] =
+{
+ "MAP_FAILED", "MAP_FIXED", "MAP_PRIVATE", "MAP_SHARED", "MCL_CURRENT",
+ "MCL_FUTURE", "MS_ASYNC", "MS_INVALIDATE", "MS_SYNC", "PROT_EXEC",
+ "PROT_NONE", "PROT_READ", "PROT_WRITE"
+};
+static const char *const mman_maybe[] =
+{
+ "mlock", "mlockall", "mmap", "mprotect", "msync", "munlock", "munlockall",
+ "munmap", "shm_open", "shm_unlock"
+};
+
+/* <sys/stat.h>. */
+static const char *const stat_syms[] =
+{
+ "S_IRGRP", "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU",
+ "S_ISBLK", "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG",
+ "S_ISUID", "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH",
+ "S_IXUSR", "S_TYPEISMQ", "S_TYPEISSEM", "S_TYPEISSHM"
+};
+static const char *const stat_maybe[] =
+{
+ "chmod", "fchmod", "fstat", "mkdir", "mkfifo", "stat", "umask"
+};
+
+/* <sys/times.h>. */
+static const char *const times_syms[] =
+{
+};
+static const char *const times_maybe[] =
+{
+ "times"
+};
+
+/* <sys/types.h>. */
+static const char *const types_syms[] =
+{
+};
+static const char *const types_maybe[] =
+{
+};
+
+/* <sys/utsname.h>. */
+static const char *const utsname_syms[] =
+{
+};
+static const char *const utsname_maybe[] =
+{
+ "uname"
+};
+
+/* <sys/wait.h>. */
+static const char *const wait_syms[] =
+{
+ "WEXITSTATUS", "WIFEXITED", "WIFSIGNALED", "WIFSTOPPED", "WNOHANG",
+ "WSTOPSIG", "WTERMSIG", "WUNTRACED"
+};
+static const char *const wait_maybe[] =
+{
+ "wait", "waitpid"
+};
+
+/* <termios.h>. */
+static const char *const termios_syms[] =
+{
+ "B0", "B110", "B1200", "B134", "B150", "B1800", "B19200", "B200", "B2400",
+ "B300", "B38400", "B4800", "B50", "B600", "B75", "B9600", "BRKINT", "CLOCAL",
+ "CREAD", "CS5", "CS6", "CS7", "CS8", "CSIZE", "CSTOPN", "ECHO", "ECHOE",
+ "ECHOK", "ECHONL", "HUPCL", "ICANON", "ICRNL", "IEXTEN", "IGNBRK", "IGNCR",
+ "IGNPAR", "INCLR", "INPCK", "ISIG", "ISTRIP", "IXOFF", "IXON", "NCCS",
+ "NOFLSH", "OPOST", "PARENB", "PARMRK", "PARODD", "TCIFLUSH", "TCIOFF",
+ "TCIOFLUSH", "TCOFLUSH", "TCOOFF", "TCOON", "TCSADRAIN", "TCSAFLUSH",
+ "TCSANOW", "TOSTOP", "VEOF", "VEOL", "VERASE", "VINTR", "VKILL", "VMIN",
+ "VQUIT", "VSTART", "VSTOP", "VSUSP", "VTIME"
+};
+static const char *const termios_maybe[] =
+{
+ "cfgetispeed", "cfgetospeed", "cfsetispeed", "cfsetospeed", "tcdrain",
+ "tcflow", "tcflush", "tcgetattr", "tcsendbrk", "tcsetattr"
+};
+
+/* <time.h>. */
+static const char *const time_syms[] =
+{
+ "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
+};
+static const char *const time_maybe[] =
+{
+ "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
+ "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
+ "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
+ "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
+ "timer_settime", "tzset"
+};
+
+/* <unistd.h>. */
+static const char *const unistd_syms[] =
+{
+ "F_OK", "NULL", "R_OK", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STDERR_FILENO",
+ "STDIN_FILENO", "STDOUT_FILENO", "W_OK", "X_OK",
+ "_PC_ASYNC_IO", "_PC_CHOWN_RESTRICTED", "_PC_LINK_MAX", "_PC_MAX_CANON",
+ "_PC_MAX_INPUT", "_PC_NAME_MAX", "_PC_NO_TRUNC", "_PC_PATH_MAX",
+ "_PC_PIPE_BUF", "_PC_PRIO_IO", "_PC_SYNC_IO", "_PC_VDISABLE",
+ "_SC_AIO_LISTIO_MAX", "_SC_AIO_MAX", "_SC_AIO_PRIO_DELTA_MAX",
+ "_SC_ARG_MAX", "_SC_ASYNCHRONOUS_IO", "_SC_CHILD_MAX", "_SC_CLK_TCK",
+ "_SC_DELAYTIMER_MAX", "_SC_FSYNC", "_SC_GETGR_R_SIZE_MAX",
+ "_SC_GETPW_R_SIZE_MAX", "_SC_JOB_CONTROL", "_SC_LOGIN_NAME_MAX",
+ "_SC_MAPPED_FILES", "_SC_MEMLOCK", "_SC_MEMLOCK_RANGE",
+ "_SC_MEMORY_PROTECTION", "_SC_MESSAGE_PASSING", "_SC_MQ_OPEN_MAX",
+ "_SC_MQ_PRIO_MAX", "_SC_NGROUPS_MAX", "_SC_OPEN_MAX", "_SC_PAGESIZE",
+ "_SC_PRIORITIZED_IO", "_SC_PRIORITY_SCHEDULING", "_SC_REALTIME_SIGNALS",
+ "_SC_RTSIG_MAX", "_SC_SAVED_IDS", "_SC_SEMAPHORES", "_SC_SEM_NSEMS_MAX",
+ "_SC_SEM_VALUE_MAX", "_SC_SHARED_MEMORY_OBJECTS", "_SC_SIGQUEUE_MAX",
+ "_SC_STREAM_MAX", "_SC_SYNCHRONIZED_IO", "_SC_THREADS",
+ "_SC_THREAD_ATTR_STACKADDR", "_SC_THREAD_ATTR_STACKSIZE",
+ "_SC_THREAD_DESTRUCTOR_ITERATIONS", "_SC_THREAD_PRIO_INHERIT",
+ "_SC_THREAD_PRIORITY_SCHEDULING", "_SC_THREAD_PRIO_PROTECT",
+ "_SC_THREAD_PROCESS_SHARED", "_SC_THREAD_SAFE_FUNCTIONS",
+ "_SC_THREAD_STACK_MIN", "_SC_THREAD_THREADS_MAX", "_SC_TIMERS",
+ "_SC_TIMER_MAX", "_SC_TTY_NAME_MAX", "_SC_TZNAME_MAX", "_SC_VERSION"
+};
+static const char *const unistd_maybe[] =
+{
+ "_POSIX_ASYNCHRONOUS_IO", "_POSIX_ASYNC_IO", "_POSIX_CHOWN_RESTRICTED",
+ "_POSIX_FSYNC", "_POSIX_JOB_CONTROL", "_POSIX_MAPPED_FILES",
+ "_POSIX_MEMLOCK", "_POSIX_MEMLOCK_RANGE", "_MEMORY_PROTECTION",
+ "_POSIX_MESSAGE_PASSING", "_POSIX_NO_TRUNC", "_POSIX_PRIORITIZED_IO",
+ "_POSIX_PRIORITY_SCHEDULING", "_POSIX_PRIO_IO", "_POSIX_REATIME_SIGNALS",
+ "_POSIX_SAVED_IDS", "_POSIX_SEMAPHORES", "_POSIX_SHARED_MEMORY_OBJECTS",
+ "_POSIX_SYNCHRONIZED_IO", "_POSIX_SYNC_IO", "_POSIX_THREADS",
+ "_POSIX_THREAD_ATTR_STACKADDR", "_POSIX_THREAD_ATTR_STACKSIZE",
+ "_POSIX_THREAD_PRIO_INHERIT", "_POSIX_THREAD_PRIO_PROTECT",
+ "_POSIX_THREAD_PROCESS_SHARED", "_POSIX_THREAD_SAFE_FUNCTIONS",
+ "_POSIX_THREAD_PRIORITY_SCHEDULING", "_POSIX_TIMERS",
+ "_POSIX_VDISABLE", "_POSIX_VERSION",
+ "_exit", "access", "alarm", "chdir", "chown", "close", "ctermid", "cuserid",
+ "dup2", "dup", "execl", "execle", "execlp", "execv", "execve", "execvp",
+ "fdatasync", "fork", "fpathconf", "fsync", "ftruncate", "getcwd", "getegid",
+ "geteuid", "getgid", "getgroups", "getlogin", "getlogin_r", "getpgrp",
+ "getpid", "getppid", "getuid", "isatty", "link", "lseek", "pathconf",
+ "pause", "pipe", "read", "rmdir", "setgid", "setgpid", "setsid", "setuid",
+ "sleep", "sleep", "sysconf", "tcgetpgrp", "tcsetpgrp", "ttyname",
+ "ttyname_r", "unlink", "write"
+};
+
+/* <utime.h>. */
+static const char *const utime_syms[] =
+{
+};
+static const char *const utime_maybe[] =
+{
+ "utime"
+};
+
+
+static struct header
+{
+ const char *name;
+ const char *const *syms;
+ size_t nsyms;
+ const char *const *maybe;
+ size_t nmaybe;
+ const char *subset;
+} headers[] =
+{
+#define H(n) \
+ { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
+ n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
+#define Hc(n, s) \
+ { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
+ n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), s }
+#define Hs(n) \
+ { "sys/" #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
+ n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
+ H(aio),
+ H(assert),
+ H(ctype),
+ H(dirent),
+ H(errno),
+ H(fcntl),
+ H(float),
+ H(grp),
+ H(limits),
+ H(locale),
+ H(math),
+ Hc(mqueue, "_POSIX_MESSAGE_PASSING"),
+ H(pthread),
+ H(pwd),
+ H(sched),
+ H(semaphore),
+ H(setjmp),
+ H(signal),
+ H(stdarg),
+ H(stddef),
+ H(stdio),
+ H(stdlib),
+ H(string),
+ Hs(mman),
+ Hs(stat),
+ Hs(times),
+ Hs(types),
+ Hs(utsname),
+ Hs(wait),
+ H(termios),
+ H(time),
+ H(unistd),
+ H(utime)
+};
+
+#define NUMBER_OF_HEADERS (sizeof headers / sizeof *headers)
+
+
+/* Format string to build command to invoke compiler. */
+static const char fmt[] = "\
+echo \"#include <%s>\" |\
+%s -E -dM -D_POSIX_SOURCE %s \
+-isystem `%s --print-prog-name=include` - > %s";
+
+static const char testfmt[] = "\
+echo \"#include <unistd.h>\n#if !defined %s || %s == -1\n#error not defined\n#endif\n\" |\
+%s -E -dM -D_POSIX_SOURCE %s \
+-isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
+
+
+/* The compiler we use (given on the command line). */
+const char *CC;
+/* The -I parameters for CC to find all headers. */
+const char *INC;
+
+static char *xstrndup (const char *, size_t);
+static const char **get_null_defines (void);
+static int check_header (const struct header *, const char **);
+static int xsystem (const char *);
+
+int
+main (int argc, char *argv[])
+{
+ int h;
+ int result = 0;
+ const char **ignore_list;
+
+ CC = argc > 1 ? argv[1] : "gcc";
+ INC = argc > 2 ? argv[2] : "";
+
+ if (system (NULL) == 0)
+ {
+ puts ("Sorry, no command processor.");
+ return EXIT_FAILURE;
+ }
+
+ /* First get list of symbols which are defined by the compiler. */
+ ignore_list = get_null_defines ();
+
+ fputs ("Tested files:\n", stdout);
+
+ for (h = 0; h < NUMBER_OF_HEADERS; ++h)
+ result |= check_header (&headers[h], ignore_list);
+
+ /* The test suite should return errors but for now this is not
+ practical. Give a warning and ask the user to correct the bugs. */
+ return result;
+}
+
+
+static char *
+xstrndup (const char *s, size_t n)
+{
+ size_t len = n;
+ char *new = malloc (len + 1);
+
+ if (new == NULL)
+ return NULL;
+
+ new[len] = '\0';
+ return memcpy (new, s, len);
+}
+
+
+/* Like system but propagate interrupt and quit signals. */
+int
+xsystem (const char *cmd)
+{
+ int status;
+
+ status = system (cmd);
+ if (status != -1)
+ {
+ if (WIFSIGNALED (status))
+ {
+ if (WTERMSIG (status) == SIGINT || WTERMSIG (status) == SIGQUIT)
+ raise (WTERMSIG (status));
+ }
+ else if (WIFEXITED (status))
+ {
+ if (WEXITSTATUS (status) == SIGINT + 128
+ || WEXITSTATUS (status) == SIGQUIT + 128)
+ raise (WEXITSTATUS (status) - 128);
+ }
+ }
+ return status;
+}
+
+
+static const char **
+get_null_defines (void)
+{
+ char line[BUFSIZ], *command;
+ char **result = NULL;
+ size_t result_len = 0;
+ size_t result_max = 0;
+ FILE *input;
+ int first = 1;
+
+ macrofile = tmpnam (NULL);
+
+ command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
+ + strlen (INC) + strlen (macrofile));
+
+ if (command == NULL)
+ {
+ puts ("No more memory.");
+ exit (1);
+ }
+
+ sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
+
+ if (xsystem (command))
+ {
+ puts ("system() returned nonzero");
+ return NULL;
+ }
+ free (command);
+ input = fopen (macrofile, "r");
+
+ if (input == NULL)
+ {
+ printf ("Could not read %s: ", macrofile);
+ perror (NULL);
+ return NULL;
+ }
+
+ while (fgets (line, sizeof line, input) != NULL)
+ {
+ char *start;
+ if (strlen (line) < 9 || line[7] != ' ')
+ { /* "#define A" */
+ printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
+ line);
+ continue;
+ }
+ if (line[8] == '_')
+ /* It's a safe identifier. */
+ continue;
+ if (result_len == result_max)
+ {
+ result_max += 10;
+ result = realloc (result, result_max * sizeof (char **));
+ if (result == NULL)
+ {
+ puts ("No more memory.");
+ exit (1);
+ }
+ }
+ start = &line[8];
+ result[result_len++] = xstrndup (start, strcspn (start, " ("));
+
+ if (first)
+ {
+ fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
+ first = 0;
+ }
+ puts (result[result_len - 1]);
+ }
+ if (result_len == result_max)
+ {
+ result_max += 1;
+ result = realloc (result, result_max * sizeof (char **));
+ if (result == NULL)
+ {
+ puts ("No more memory.");
+ exit (1);
+ }
+ }
+ result[result_len] = NULL;
+ fclose (input);
+ remove (macrofile);
+
+ return (const char **) result;
+}
+
+
+static int
+check_header (const struct header *header, const char **except)
+{
+ char line[BUFSIZ], command[sizeof fmt + strlen (header->name)
+ + 2 * strlen (CC)
+ + strlen (INC) + strlen (macrofile)];
+ FILE *input;
+ int result = 0;
+ int found[header->nsyms];
+ int i;
+
+ memset (found, '\0', header->nsyms * sizeof (int));
+
+ printf ("=== %s ===\n", header->name);
+ sprintf (command, fmt, header->name, CC, INC, CC, macrofile);
+
+ /* First see whether this subset is supported at all. */
+ if (header->subset != NULL)
+ {
+ sprintf (line, testfmt, header->subset, header->subset, CC, INC, CC,
+ macrofile);
+ if (xsystem (line))
+ {
+ printf ("!! not available\n");
+ return 0;
+ }
+ }
+
+ if (xsystem (command))
+ {
+ puts ("system() returned nonzero");
+ result = 1;
+ }
+ input = fopen (macrofile, "r");
+
+ if (input == NULL)
+ {
+ printf ("Could not read %s: ", macrofile);
+ perror (NULL);
+ return 1;
+ }
+
+ while (fgets (line, sizeof line, input) != NULL)
+ {
+ const char **ignore;
+ if (strlen (line) < 9 || line[7] != ' ')
+ { /* "#define A" */
+ printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
+ line);
+ result = 1;
+ continue;
+ }
+
+ /* Find next char after the macro identifier; this can be either
+ a space or an open parenthesis. */
+ line[8 + strcspn (&line[8], " (")] = '\0';
+
+ /* Now check whether it's one of the required macros. */
+ for (i = 0; i < header->nsyms; ++i)
+ if (!strcmp (&line[8], header->syms[i]))
+ break;
+ if (i < header->nsyms)
+ {
+ found[i] = 1;
+ continue;
+ }
+
+ /* Symbols starting with "_" are ok. */
+ if (line[8] == '_')
+ continue;
+
+ /* Maybe one of the symbols which are always defined. */
+ for (ignore = except; *ignore != NULL; ++ignore)
+ if (! strcmp (&line[8], *ignore))
+ break;
+ if (*ignore != NULL)
+ continue;
+
+ /* Otherwise the symbol better should match one of the following. */
+ for (i = 0; i < header->nmaybe; ++i)
+ if (fnmatch (header->maybe[i], &line[8], 0) == 0)
+ break;
+ if (i < header->nmaybe)
+ continue;
+
+ printf ("* invalid macro `%s'\n", &line[8]);
+ result |= 1;
+ }
+ fclose (input);
+ remove (macrofile);
+
+ for (i = 0; i < header->nsyms; ++i)
+ if (found[i] == 0)
+ printf ("** macro `%s' not defined\n", header->syms[i]);
+
+ return result;
+}
diff --git a/libc/posix/bits/posix1_lim.h b/libc/posix/bits/posix1_lim.h
new file mode 100644
index 000000000..71c58f760
--- /dev/null
+++ b/libc/posix/bits/posix1_lim.h
@@ -0,0 +1,168 @@
+/* Copyright (C) 1991-1993,96,98,2000-2003,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 2.9.2 Minimum Values Added to <limits.h>
+ *
+ * Never include this file directly; use <limits.h> instead.
+ */
+
+#ifndef _BITS_POSIX1_LIM_H
+#define _BITS_POSIX1_LIM_H 1
+
+
+/* These are the standard-mandated minimum values. */
+
+/* Minimum number of operations in one list I/O call. */
+#define _POSIX_AIO_LISTIO_MAX 2
+
+/* Minimal number of outstanding asynchronous I/O operations. */
+#define _POSIX_AIO_MAX 1
+
+/* Maximum length of arguments to `execve', including environment. */
+#define _POSIX_ARG_MAX 4096
+
+/* Maximum simultaneous processes per real user ID. */
+#ifdef __USE_XOPEN2K
+# define _POSIX_CHILD_MAX 25
+#else
+# define _POSIX_CHILD_MAX 6
+#endif
+
+/* Minimal number of timer expiration overruns. */
+#define _POSIX_DELAYTIMER_MAX 32
+
+/* Maximum length of a host name (not including the terminating null)
+ as returned from the GETHOSTNAME function. */
+#define _POSIX_HOST_NAME_MAX 255
+
+/* Maximum link count of a file. */
+#define _POSIX_LINK_MAX 8
+
+/* Maximum length of login name. */
+#define _POSIX_LOGIN_NAME_MAX 9
+
+/* Number of bytes in a terminal canonical input queue. */
+#define _POSIX_MAX_CANON 255
+
+/* Number of bytes for which space will be
+ available in a terminal input queue. */
+#define _POSIX_MAX_INPUT 255
+
+/* Maximum number of message queues open for a process. */
+#define _POSIX_MQ_OPEN_MAX 8
+
+/* Maximum number of supported message priorities. */
+#define _POSIX_MQ_PRIO_MAX 32
+
+/* Number of bytes in a filename. */
+#define _POSIX_NAME_MAX 14
+
+/* Number of simultaneous supplementary group IDs per process. */
+#ifdef __USE_XOPEN2K
+# define _POSIX_NGROUPS_MAX 8
+#else
+# define _POSIX_NGROUPS_MAX 0
+#endif
+
+/* Number of files one process can have open at once. */
+#ifdef __USE_XOPEN2K
+# define _POSIX_OPEN_MAX 20
+#else
+# define _POSIX_OPEN_MAX 16
+#endif
+
+/* Number of descriptors that a process may examine with `pselect' or
+ `select'. */
+#define _POSIX_FD_SETSIZE _POSIX_OPEN_MAX
+
+/* Number of bytes in a pathname. */
+#define _POSIX_PATH_MAX 256
+
+/* Number of bytes than can be written atomically to a pipe. */
+#define _POSIX_PIPE_BUF 512
+
+/* The number of repeated occurrences of a BRE permitted by the
+ REGEXEC and REGCOMP functions when using the interval notation. */
+#define _POSIX_RE_DUP_MAX 255
+
+/* Minimal number of realtime signals reserved for the application. */
+#define _POSIX_RTSIG_MAX 8
+
+/* Number of semaphores a process can have. */
+#define _POSIX_SEM_NSEMS_MAX 256
+
+/* Maximal value of a semaphore. */
+#define _POSIX_SEM_VALUE_MAX 32767
+
+/* Number of pending realtime signals. */
+#define _POSIX_SIGQUEUE_MAX 32
+
+/* Largest value of a `ssize_t'. */
+#define _POSIX_SSIZE_MAX 32767
+
+/* Number of streams a process can have open at once. */
+#define _POSIX_STREAM_MAX 8
+
+/* The number of bytes in a symbolic link. */
+#define _POSIX_SYMLINK_MAX 255
+
+/* The number of symbolic links that can be traversed in the
+ resolution of a pathname in the absence of a loop. */
+#define _POSIX_SYMLOOP_MAX 8
+
+/* Number of timer for a process. */
+#define _POSIX_TIMER_MAX 32
+
+/* Maximum number of characters in a tty name. */
+#define _POSIX_TTY_NAME_MAX 9
+
+/* Maximum length of a timezone name (element of `tzname'). */
+#define _POSIX_TZNAME_MAX 6
+
+/* Maximum number of connections that can be queued on a socket. */
+#define _POSIX_QLIMIT 1
+
+/* Maximum number of bytes that can be buffered on a socket for send
+ or receive. */
+#define _POSIX_HIWAT _POSIX_PIPE_BUF
+
+/* Maximum number of elements in an `iovec' array. */
+#define _POSIX_UIO_MAXIOV 16
+
+/* Maximum clock resolution in nanoseconds. */
+#define _POSIX_CLOCKRES_MIN 20000000
+
+
+/* Get the implementation-specific values for the above. */
+#include <bits/local_lim.h>
+
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX LONG_MAX
+#endif
+
+
+/* This value is a guaranteed minimum maximum.
+ The current maximum can be got from `sysconf'. */
+
+#ifndef NGROUPS_MAX
+# define NGROUPS_MAX 8
+#endif
+
+#endif /* bits/posix1_lim.h */
diff --git a/libc/posix/bits/posix2_lim.h b/libc/posix/bits/posix2_lim.h
new file mode 100644
index 000000000..24483a09d
--- /dev/null
+++ b/libc/posix/bits/posix2_lim.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 1991, 1996, 1999, 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * Never include this file directly; include <limits.h> instead.
+ */
+
+#ifndef _BITS_POSIX2_LIM_H
+#define _BITS_POSIX2_LIM_H 1
+
+
+/* The maximum `ibase' and `obase' values allowed by the `bc' utility. */
+#define _POSIX2_BC_BASE_MAX 99
+
+/* The maximum number of elements allowed in an array by the `bc' utility. */
+#define _POSIX2_BC_DIM_MAX 2048
+
+/* The maximum `scale' value allowed by the `bc' utility. */
+#define _POSIX2_BC_SCALE_MAX 99
+
+/* The maximum length of a string constant accepted by the `bc' utility. */
+#define _POSIX2_BC_STRING_MAX 1000
+
+/* The maximum number of weights that can be assigned to an entry of
+ the LC_COLLATE `order' keyword in the locale definition file. */
+#define _POSIX2_COLL_WEIGHTS_MAX 2
+
+/* The maximum number of expressions that can be nested
+ within parentheses by the `expr' utility. */
+#define _POSIX2_EXPR_NEST_MAX 32
+
+/* The maximum length, in bytes, of an input line. */
+#define _POSIX2_LINE_MAX 2048
+
+/* The maximum number of repeated occurrences of a regular expression
+ permitted when using the interval notation `\{M,N\}'. */
+#define _POSIX2_RE_DUP_MAX 255
+
+/* The maximum number of bytes in a character class name. We have no
+ fixed limit, 2048 is a high number. */
+#define _POSIX2_CHARCLASS_NAME_MAX 14
+
+
+/* These values are implementation-specific,
+ and may vary within the implementation.
+ Their precise values can be obtained from sysconf. */
+
+#ifndef BC_BASE_MAX
+#define BC_BASE_MAX _POSIX2_BC_BASE_MAX
+#endif
+#ifndef BC_DIM_MAX
+#define BC_DIM_MAX _POSIX2_BC_DIM_MAX
+#endif
+#ifndef BC_SCALE_MAX
+#define BC_SCALE_MAX _POSIX2_BC_SCALE_MAX
+#endif
+#ifndef BC_STRING_MAX
+#define BC_STRING_MAX _POSIX2_BC_STRING_MAX
+#endif
+#ifndef COLL_WEIGHTS_MAX
+#define COLL_WEIGHTS_MAX 255
+#endif
+#ifndef EXPR_NEST_MAX
+#define EXPR_NEST_MAX _POSIX2_EXPR_NEST_MAX
+#endif
+#ifndef LINE_MAX
+#define LINE_MAX _POSIX2_LINE_MAX
+#endif
+#ifndef CHARCLASS_NAME_MAX
+#define CHARCLASS_NAME_MAX 2048
+#endif
+
+/* This value is defined like this in regex.h. */
+#define RE_DUP_MAX (0x7fff)
+
+#endif /* bits/posix2_lim.h */
diff --git a/libc/posix/bits/unistd.h b/libc/posix/bits/unistd.h
new file mode 100644
index 000000000..96f26d548
--- /dev/null
+++ b/libc/posix/bits/unistd.h
@@ -0,0 +1,250 @@
+/* Checking macros for unistd functions.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _UNISTD_H
+# error "Never include <bits/unistd.h> directly; use <unistd.h> instead."
+#endif
+
+extern ssize_t __read_chk (int __fd, void *__buf, size_t __nbytes,
+ size_t __buflen) __wur;
+extern ssize_t __REDIRECT (__read_alias, (int __fd, void *__buf,
+ size_t __nbytes), read) __wur;
+
+extern __always_inline __wur ssize_t
+read (int __fd, void *__buf, size_t __nbytes)
+{
+ if (__bos0 (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf)))
+ return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf));
+ return __read_alias (__fd, __buf, __nbytes);
+}
+
+#ifdef __USE_UNIX98
+extern ssize_t __pread_chk (int __fd, void *__buf, size_t __nbytes,
+ __off_t __offset, size_t __bufsize) __wur;
+extern ssize_t __pread64_chk (int __fd, void *__buf, size_t __nbytes,
+ __off64_t __offset, size_t __bufsize) __wur;
+extern ssize_t __REDIRECT (__pread_alias,
+ (int __fd, void *__buf, size_t __nbytes,
+ __off_t __offset), pread) __wur;
+extern ssize_t __REDIRECT (__pread64_alias,
+ (int __fd, void *__buf, size_t __nbytes,
+ __off64_t __offset), pread64) __wur;
+
+# ifndef __USE_FILE_OFFSET64
+extern __always_inline __wur ssize_t
+pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
+{
+ if (__bos0 (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf)))
+ return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
+ return __pread_alias (__fd, __buf, __nbytes, __offset);
+}
+# else
+extern __always_inline __wur ssize_t
+pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+{
+ if (__bos0 (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf)))
+ return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
+ return __pread64_alias (__fd, __buf, __nbytes, __offset);
+}
+# endif
+
+# ifdef __USE_LARGEFILE64
+extern __always_inline __wur ssize_t
+pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+{
+ if (__bos0 (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf)))
+ return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
+ return __pread64_alias (__fd, __buf, __nbytes, __offset);
+}
+# endif
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
+extern ssize_t __readlink_chk (__const char *__restrict __path,
+ char *__restrict __buf, size_t __len,
+ size_t __buflen)
+ __THROW __nonnull ((1, 2)) __wur;
+extern ssize_t __REDIRECT_NTH (__readlink_alias,
+ (__const char *__restrict __path,
+ char *__restrict __buf, size_t __len), readlink)
+ __nonnull ((1, 2)) __wur;
+
+extern __always_inline __nonnull ((1, 2)) __wur ssize_t
+__NTH (readlink (__const char *__restrict __path, char *__restrict __buf,
+ size_t __len))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__len) || __len > __bos (__buf)))
+ return __readlink_chk (__path, __buf, __len, __bos (__buf));
+ return __readlink_alias (__path, __buf, __len);
+}
+#endif
+
+#ifdef __USE_ATFILE
+extern ssize_t __readlinkat_chk (int __fd, __const char *__restrict __path,
+ char *__restrict __buf, size_t __len,
+ size_t __buflen)
+ __THROW __nonnull ((2, 3)) __wur;
+extern ssize_t __REDIRECT_NTH (__readlinkat_alias,
+ (int __fd, __const char *__restrict __path,
+ char *__restrict __buf, size_t __len),
+ readlinkat)
+ __nonnull ((2, 3)) __wur;
+
+extern __always_inline __nonnull ((2, 3)) __wur ssize_t
+__NTH (readlinkat (int __fd, __const char *__restrict __path,
+ char *__restrict __buf, size_t __len))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__len) || __len > __bos (__buf)))
+ return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf));
+ return __readlinkat_alias (__fd, __path, __buf, __len);
+}
+#endif
+
+extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
+ __THROW __wur;
+extern char *__REDIRECT_NTH (__getcwd_alias,
+ (char *__buf, size_t __size), getcwd) __wur;
+
+extern __always_inline __wur char *
+__NTH (getcwd (char *__buf, size_t __size))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__size) || __size > __bos (__buf)))
+ return __getcwd_chk (__buf, __size, __bos (__buf));
+ return __getcwd_alias (__buf, __size);
+}
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+extern char *__getwd_chk (char *__buf, size_t buflen)
+ __THROW __nonnull ((1)) __wur;
+extern char *__REDIRECT_NTH (__getwd_alias, (char *__buf), getwd)
+ __nonnull ((1)) __wur;
+
+extern __always_inline __nonnull ((1)) __attribute_deprecated__ __wur char *
+__NTH (getwd (char *__buf))
+{
+ if (__bos (__buf) != (size_t) -1)
+ return __getwd_chk (__buf, __bos (__buf));
+ return __getwd_alias (__buf);
+}
+#endif
+
+extern size_t __confstr_chk (int __name, char *__buf, size_t __len,
+ size_t __buflen) __THROW;
+extern size_t __REDIRECT_NTH (__confstr_alias, (int __name, char *__buf,
+ size_t __len), confstr);
+
+extern __always_inline size_t
+__NTH (confstr (int __name, char *__buf, size_t __len))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__len) || __bos (__buf) < __len))
+ return __confstr_chk (__name, __buf, __len, __bos (__buf));
+ return __confstr_alias (__name, __buf, __len);
+}
+
+
+extern int __getgroups_chk (int __size, __gid_t __list[], size_t listlen)
+ __THROW __wur;
+extern int __REDIRECT_NTH (__getgroups_alias, (int __size, __gid_t __list[]),
+ getgroups) __wur;
+
+extern __always_inline int
+__NTH (getgroups (int __size, __gid_t __list[]))
+{
+ if (__bos (__list) != (size_t) -1
+ && (!__builtin_constant_p (__size)
+ || __size * sizeof (__gid_t) > __bos (__list)))
+ return __getgroups_chk (__size, __list, __bos (__list));
+ return __getgroups_alias (__size, __list);
+}
+
+
+extern int __ttyname_r_chk (int __fd, char *__buf, size_t __buflen,
+ size_t __nreal) __THROW __nonnull ((2));
+extern int __REDIRECT_NTH (__ttyname_r_alias, (int __fd, char *__buf,
+ size_t __buflen), ttyname_r)
+ __nonnull ((2));
+
+extern __always_inline int
+__NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf)))
+ return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf));
+ return __ttyname_r_alias (__fd, __buf, __buflen);
+}
+
+
+#if defined __USE_REENTRANT || defined __USE_UNIX98
+extern int __getlogin_r_chk (char *__buf, size_t __buflen, size_t __nreal)
+ __nonnull ((1));
+extern int __REDIRECT (__getlogin_r_alias, (char *__buf, size_t __buflen),
+ getlogin_r) __nonnull ((1));
+
+extern __always_inline int
+getlogin_r (char *__buf, size_t __buflen)
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf)))
+ return __getlogin_r_chk (__buf, __buflen, __bos (__buf));
+ return __getlogin_r_alias (__buf, __buflen);
+}
+#endif
+
+
+#if defined __USE_BSD || defined __USE_UNIX98
+extern int __gethostname_chk (char *__buf, size_t __buflen, size_t __nreal)
+ __THROW __nonnull ((1));
+extern int __REDIRECT_NTH (__gethostname_alias, (char *__buf, size_t __buflen),
+ gethostname) __nonnull ((1));
+
+extern __always_inline int
+__NTH (gethostname (char *__buf, size_t __buflen))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf)))
+ return __gethostname_chk (__buf, __buflen, __bos (__buf));
+ return __gethostname_alias (__buf, __buflen);
+}
+#endif
+
+
+#if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98)
+extern int __getdomainname_chk (char *__buf, size_t __buflen, size_t __nreal)
+ __THROW __nonnull ((1)) __wur;
+extern int __REDIRECT_NTH (__getdomainname_alias, (char *__buf,
+ size_t __buflen),
+ getdomainname) __nonnull ((1)) __wur;
+
+extern __always_inline int
+__NTH (getdomainname (char *__buf, size_t __buflen))
+{
+ if (__bos (__buf) != (size_t) -1
+ && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf)))
+ return __getdomainname_chk (__buf, __buflen, __bos (__buf));
+ return __getdomainname_alias (__buf, __buflen);
+}
+#endif
diff --git a/libc/posix/bsd-getpgrp.c b/libc/posix/bsd-getpgrp.c
new file mode 100644
index 000000000..967b92d47
--- /dev/null
+++ b/libc/posix/bsd-getpgrp.c
@@ -0,0 +1,32 @@
+/* BSD-compatible versions of getpgrp function.
+ Copyright (C) 1991,92,94,95,96,97,2000,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+
+/* Don't include unistd.h because it declares a conflicting
+ prototype for the POSIX.1 `getpgrp' function. */
+extern pid_t __getpgid (pid_t);
+libc_hidden_proto (__getpgid)
+extern pid_t __bsd_getpgrp (pid_t);
+
+pid_t
+__bsd_getpgrp (pid_t pid)
+{
+ return __getpgid (pid);
+}
diff --git a/libc/posix/bug-ga1.c b/libc/posix/bug-ga1.c
new file mode 100644
index 000000000..c46ab43fd
--- /dev/null
+++ b/libc/posix/bug-ga1.c
@@ -0,0 +1,23 @@
+/* Test case by Anders Carlsson <andersca@gnome.org>. */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+ struct addrinfo req, *ai;
+ char name[] = "3ffe:0200:0064:0000:0202:b3ff:fe16:ddc5";
+
+ memset (&req, '\0', sizeof req);
+ req.ai_family = AF_INET6;
+
+ /* This call used to crash. We cannot expect the test machine to have
+ IPv6 enabled so we just check that the call returns. */
+ getaddrinfo (name, NULL, &req, &ai);
+
+ puts ("success!");
+ return 0;
+}
diff --git a/libc/posix/bug-ga2.c b/libc/posix/bug-ga2.c
new file mode 100644
index 000000000..5ea759b8c
--- /dev/null
+++ b/libc/posix/bug-ga2.c
@@ -0,0 +1,30 @@
+/* Test case by Sam Varshavchik <mrsam@courier-mta.com>. */
+#include <mcheck.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+ struct addrinfo hints, *res;
+ int i, ret;
+
+ mtrace ();
+ for (i = 0; i < 100; i++)
+ {
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ ret = getaddrinfo ("www.gnu.org", "http", &hints, &res);
+
+ if (ret)
+ {
+ printf ("%s\n", gai_strerror (ret));
+ return 1;
+ }
+ freeaddrinfo (res);
+ }
+ return 0;
+}
diff --git a/libc/posix/bug-glob1.c b/libc/posix/bug-glob1.c
new file mode 100644
index 000000000..05c2da758
--- /dev/null
+++ b/libc/posix/bug-glob1.c
@@ -0,0 +1,88 @@
+/* Test case for globbing dangling symlink. By Ulrich Drepper. */
+#include <errno.h>
+#include <error.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static void prepare (int argc, char *argv[]);
+#define PREPARE prepare
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+
+static char *fname;
+
+static void
+prepare (int argc, char *argv[])
+{
+ if (argc < 2)
+ error (EXIT_FAILURE, 0, "missing argument");
+
+ size_t len = strlen (argv[1]);
+ static const char ext[] = "globXXXXXX";
+ fname = malloc (len + sizeof (ext));
+ if (fname == NULL)
+ error (EXIT_FAILURE, errno, "cannot create temp file");
+ again:
+ strcpy (stpcpy (fname, argv[1]), ext);
+ fname = mktemp (fname);
+ if (fname == NULL || *fname == '\0')
+ error (EXIT_FAILURE, errno, "cannot create temp file name");
+ if (symlink ("bug-glob1-does-not-exist", fname) != 0)
+ {
+ if (errno == EEXIST)
+ goto again;
+
+ error (EXIT_FAILURE, errno, "cannot create symlink");
+ }
+ add_temp_file (fname);
+}
+
+
+static int
+do_test (void)
+{
+ glob_t gl;
+ int retval = 0;
+ int e;
+
+ e = glob (fname, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded\n", fname);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ size_t fnamelen = strlen (fname);
+ char buf[fnamelen + 2];
+
+ strcpy (buf, fname);
+ buf[fnamelen - 1] = '?';
+ e = glob (buf, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded\n", buf);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ strcpy (buf, fname);
+ buf[fnamelen] = '*';
+ buf[fnamelen + 1] = '\0';
+ e = glob (buf, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded\n", buf);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ return retval;
+}
diff --git a/libc/posix/bug-glob2.c b/libc/posix/bug-glob2.c
new file mode 100644
index 000000000..88e3558e3
--- /dev/null
+++ b/libc/posix/bug-glob2.c
@@ -0,0 +1,303 @@
+/* Test glob memory management.
+ for the filesystem access functions.
+ Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <dirent.h>
+#include <glob.h>
+#include <mcheck.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+// #define DEBUG
+#ifdef DEBUG
+# define PRINTF(fmt, args...) \
+ do \
+ { \
+ int save_errno = errno; \
+ printf (fmt, ##args); \
+ errno = save_errno; \
+ } while (0)
+#else
+# define PRINTF(fmt, args...)
+#endif
+
+
+static struct
+{
+ const char *name;
+ int level;
+ int type;
+ mode_t mode;
+} filesystem[] =
+{
+ { ".", 1, DT_DIR, 0755 },
+ { "..", 1, DT_DIR, 0755 },
+ { "dir", 1, DT_DIR, 0755 },
+ { ".", 2, DT_DIR, 0755 },
+ { "..", 2, DT_DIR, 0755 },
+ { "readable", 2, DT_DIR, 0755 },
+ { ".", 3, DT_DIR, 0755 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 },
+ { "unreadable", 2, DT_DIR, 0111 },
+ { ".", 3, DT_DIR, 0111 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 },
+ { "zz-readable", 2, DT_DIR, 0755 },
+ { ".", 3, DT_DIR, 0755 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 }
+};
+#define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
+
+
+typedef struct
+{
+ int level;
+ int idx;
+ struct dirent d;
+ char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+
+static long int
+find_file (const char *s)
+{
+ int level = 1;
+ long int idx = 0;
+
+ if (strcmp (s, ".") == 0)
+ return 0;
+
+ if (s[0] == '.' && s[1] == '/')
+ s += 2;
+
+ while (*s != '\0')
+ {
+ char *endp = strchrnul (s, '/');
+
+ PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
+
+ while (idx < nfiles && filesystem[idx].level >= level)
+ {
+ if (filesystem[idx].level == level
+ && memcmp (s, filesystem[idx].name, endp - s) == 0
+ && filesystem[idx].name[endp - s] == '\0')
+ break;
+ ++idx;
+ }
+
+ if (idx == nfiles || filesystem[idx].level < level)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (*endp == '\0')
+ return idx + 1;
+
+ if (filesystem[idx].type != DT_DIR
+ && (idx + 1 >= nfiles
+ || filesystem[idx].level >= filesystem[idx + 1].level))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ ++idx;
+
+ s = endp + 1;
+ ++level;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+
+static void *
+my_opendir (const char *s)
+{
+ long int idx = find_file (s);
+ my_DIR *dir;
+
+ if (idx == -1)
+ {
+ PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
+ return NULL;
+ }
+
+ if ((filesystem[idx].mode & 0400) == 0)
+ {
+ errno = EACCES;
+ PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
+ return NULL;
+ }
+
+ dir = (my_DIR *) malloc (sizeof (my_DIR));
+ if (dir == NULL)
+ {
+ printf ("cannot allocate directory handle: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ dir->level = filesystem[idx].level;
+ dir->idx = idx;
+
+ PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
+ s, filesystem[idx].level, idx);
+
+ return dir;
+}
+
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+ my_DIR *dir = gdir;
+
+ if (dir->idx == -1)
+ {
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+ ++dir->idx;
+
+ if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+ {
+ dir->idx = -1;
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ dir->d.d_ino = dir->idx;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+ strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
+ dir->d.d_name);
+#else
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino,
+ dir->d.d_name);
+#endif
+
+ ++dir->idx;
+
+ return &dir->d;
+}
+
+
+static void
+my_closedir (void *dir)
+{
+ PRINTF ("my_closedir ()\n");
+ free (dir);
+}
+
+
+/* We use this function for lstat as well since we don't have any. */
+static int
+my_stat (const char *name, struct stat *st)
+{
+ long int idx = find_file (name);
+
+ if (idx == -1)
+ {
+ PRINTF ("my_stat (\"%s\", ...) = -1 (%m)\n", name);
+ return -1;
+ }
+
+ memset (st, '\0', sizeof (*st));
+
+ if (filesystem[idx].type == DT_UNKNOWN)
+ st->st_mode = DTTOIF (idx + 1 < nfiles
+ && filesystem[idx].level < filesystem[idx + 1].level
+ ? DT_DIR : DT_REG) | filesystem[idx].mode;
+ else
+ st->st_mode = DTTOIF (filesystem[idx].type) | filesystem[idx].mode;
+
+ PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
+
+ return 0;
+}
+
+
+static void
+init_glob_altdirfuncs (glob_t *pglob)
+{
+ pglob->gl_closedir = my_closedir;
+ pglob->gl_readdir = my_readdir;
+ pglob->gl_opendir = my_opendir;
+ pglob->gl_lstat = my_stat;
+ pglob->gl_stat = my_stat;
+}
+
+
+int
+do_test (void)
+{
+ mtrace ();
+
+ glob_t gl;
+ memset (&gl, 0, sizeof (gl));
+ init_glob_altdirfuncs (&gl);
+
+ if (glob ("dir/*able/*", GLOB_ERR | GLOB_ALTDIRFUNC, NULL, &gl)
+ != GLOB_ABORTED)
+ {
+ puts ("glob did not fail with GLOB_ABORTED");
+ exit (EXIT_FAILURE);
+ }
+
+ globfree (&gl);
+
+ memset (&gl, 0, sizeof (gl));
+ init_glob_altdirfuncs (&gl);
+
+ gl.gl_offs = 3;
+ if (glob ("dir2/*", GLOB_DOOFFS, NULL, &gl) != GLOB_NOMATCH)
+ {
+ puts ("glob did not fail with GLOB_NOMATCH");
+ exit (EXIT_FAILURE);
+ }
+
+ globfree (&gl);
+
+ muntrace ();
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/bug-regex1.c b/libc/posix/bug-regex1.c
new file mode 100644
index 000000000..38eb54395
--- /dev/null
+++ b/libc/posix/bug-regex1.c
@@ -0,0 +1,65 @@
+/* Test case by Jim Meyering <jim@meyering.net>. */
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+#include <wchar.h>
+
+int
+main (void)
+{
+ struct re_pattern_buffer regex;
+ struct re_registers regs;
+ const char *s;
+ int match;
+ int result = 0;
+
+ memset (&regex, '\0', sizeof (regex));
+
+ setlocale (LC_ALL, "de_DE.ISO-8859-1");
+ fwide (stdout, -1);
+
+ re_set_syntax (RE_SYNTAX_POSIX_EGREP | RE_DEBUG);
+
+ puts ("in C locale");
+ setlocale (LC_ALL, "C");
+ s = re_compile_pattern ("[anù]*n", 7, &regex);
+ if (s != NULL)
+ {
+ puts ("re_compile_pattern return non-NULL value");
+ result = 1;
+ }
+ else
+ {
+ match = re_match (&regex, "an", 2, 0, &regs);
+ if (match != 2)
+ {
+ printf ("re_match returned %d, expected 2\n", match);
+ result = 1;
+ }
+ else
+ puts (" -> OK");
+ }
+
+ puts ("in de_DE.ISO-8859-1 locale");
+ setlocale (LC_ALL, "de_DE.ISO-8859-1");
+ s = re_compile_pattern ("[anù]*n", 7, &regex);
+ if (s != NULL)
+ {
+ puts ("re_compile_pattern return non-NULL value");
+ result = 1;
+ }
+ else
+ {
+ match = re_match (&regex, "an", 2, 0, &regs);
+ if (match != 2)
+ {
+ printf ("re_match returned %d, expected 2\n", match);
+ result = 1;
+ }
+ else
+ puts (" -> OK");
+ }
+
+ return result;
+}
diff --git a/libc/posix/bug-regex10.c b/libc/posix/bug-regex10.c
new file mode 100644
index 000000000..5cb01465a
--- /dev/null
+++ b/libc/posix/bug-regex10.c
@@ -0,0 +1,61 @@
+/* Test for re_match with non-zero start.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+
+int
+main (void)
+{
+ struct re_pattern_buffer regex;
+ struct re_registers regs;
+ const char *s;
+ int match;
+ int result = 0;
+
+ regs.num_regs = 1;
+ memset (&regex, '\0', sizeof (regex));
+ s = re_compile_pattern ("[abc]*d", 7, &regex);
+ if (s != NULL)
+ {
+ puts ("re_compile_pattern return non-NULL value");
+ result = 1;
+ }
+ else
+ {
+ match = re_match (&regex, "foacabdxy", 9, 2, &regs);
+ if (match != 5)
+ {
+ printf ("re_match returned %d, expected 5\n", match);
+ result = 1;
+ }
+ else if (regs.start[0] != 2 || regs.end[0] != 7)
+ {
+ printf ("re_match returned %d..%d, expected 2..7\n",
+ regs.start[0], regs.end[0]);
+ result = 1;
+ }
+ puts (" -> OK");
+ }
+
+ return result;
+}
diff --git a/libc/posix/bug-regex11.c b/libc/posix/bug-regex11.c
new file mode 100644
index 000000000..fdc78f941
--- /dev/null
+++ b/libc/posix/bug-regex11.c
@@ -0,0 +1,139 @@
+/* Regular expression tests.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Tests supposed to match. */
+struct
+{
+ const char *pattern;
+ const char *string;
+ int flags, nmatch;
+ regmatch_t rm[5];
+} tests[] = {
+ /* Test for newline handling in regex. */
+ { "[^~]*~", "\nx~y", 0, 2, { { 0, 3 }, { -1, -1 } } },
+ /* Other tests. */
+ { "a(.*)b", "a b", REG_EXTENDED, 2, { { 0, 3 }, { 1, 2 } } },
+ { ".*|\\([KIO]\\)\\([^|]*\\).*|?[KIO]", "10~.~|P|K0|I10|O16|?KSb", 0, 3,
+ { { 0, 21 }, { 15, 16 }, { 16, 18 } } },
+ { ".*|\\([KIO]\\)\\([^|]*\\).*|?\\1", "10~.~|P|K0|I10|O16|?KSb", 0, 3,
+ { { 0, 21 }, { 8, 9 }, { 9, 10 } } },
+ { "^\\(a*\\)\\1\\{9\\}\\(a\\{0,9\\}\\)\\([0-9]*;.*[^a]\\2\\([0-9]\\)\\)",
+ "a1;;0a1aa2aaa3aaaa4aaaaa5aaaaaa6aaaaaaa7aaaaaaaa8aaaaaaaaa9aa2aa1a0", 0,
+ 5, { { 0, 67 }, { 0, 0 }, { 0, 1 }, { 1, 67 }, { 66, 67 } } },
+ /* Test for BRE expression anchoring. POSIX says just that this may match;
+ in glibc regex it always matched, so avoid changing it. */
+ { "\\(^\\|foo\\)bar", "bar", 0, 2, { { 0, 3 }, { -1, -1 } } },
+ { "\\(foo\\|^\\)bar", "bar", 0, 2, { { 0, 3 }, { -1, -1 } } },
+ /* In ERE this must be treated as an anchor. */
+ { "(^|foo)bar", "bar", REG_EXTENDED, 2, { { 0, 3 }, { -1, -1 } } },
+ { "(foo|^)bar", "bar", REG_EXTENDED, 2, { { 0, 3 }, { -1, -1 } } },
+ /* Here ^ cannot be treated as an anchor according to POSIX. */
+ { "(^|foo)bar", "(^|foo)bar", 0, 2, { { 0, 10 }, { -1, -1 } } },
+ { "(foo|^)bar", "(foo|^)bar", 0, 2, { { 0, 10 }, { -1, -1 } } },
+ /* More tests on backreferences. */
+ { "()\\1", "x", REG_EXTENDED, 2, { { 0, 0 }, { 0, 0 } } },
+ { "()x\\1", "x", REG_EXTENDED, 2, { { 0, 1 }, { 0, 0 } } },
+ { "()\\1*\\1*", "", REG_EXTENDED, 2, { { 0, 0 }, { 0, 0 } } },
+ { "([0-9]).*\\1(a*)", "7;7a6", REG_EXTENDED, 3, { { 0, 4 }, { 0, 1 }, { 3, 4 } } },
+ { "([0-9]).*\\1(a*)", "7;7a", REG_EXTENDED, 3, { { 0, 4 }, { 0, 1 }, { 3, 4 } } },
+ { "(b)()c\\1", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 1 }, { 1, 1 } } },
+ { "()(b)c\\2", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 0 }, { 0, 1 } } },
+ { "a(b)()c\\1", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 2 }, { 2, 2 } } },
+ { "a()(b)c\\2", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 1 }, { 1, 2 } } },
+ { "()(b)\\1c\\2", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 0 }, { 0, 1 } } },
+ { "(b())\\2\\1", "bbbb", REG_EXTENDED, 3, { { 0, 2 }, { 0, 1 }, { 1, 1 } } },
+ { "a()(b)\\1c\\2", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 1 }, { 1, 2 } } },
+ { "a()d(b)\\1c\\2", "adbcb", REG_EXTENDED, 3, { { 0, 5 }, { 1, 1 }, { 2, 3 } } },
+ { "a(b())\\2\\1", "abbbb", REG_EXTENDED, 3, { { 0, 3 }, { 1, 2 }, { 2, 2 } } },
+ { "(bb())\\2\\1", "bbbb", REG_EXTENDED, 3, { { 0, 4 }, { 0, 2 }, { 2, 2 } } },
+ { "^([^,]*),\\1,\\1$", "a,a,a", REG_EXTENDED, 2, { { 0, 5 }, { 0, 1 } } },
+ { "^([^,]*),\\1,\\1$", "ab,ab,ab", REG_EXTENDED, 2, { { 0, 8 }, { 0, 2 } } },
+ { "^([^,]*),\\1,\\1,\\1$", "abc,abc,abc,abc", REG_EXTENDED, 2,
+ { { 0, 15 }, { 0, 3 } } },
+ { "^(.?)(.?)(.?)(.?)(.?).?\\5\\4\\3\\2\\1$",
+ "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } },
+ { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$",
+ "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } },
+ { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$",
+ "abcdedcba", REG_EXTENDED, 1, { { 0, 9 } } },
+#if 0
+ /* XXX Not used since they fail so far. */
+ { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$",
+ "ababababa", REG_EXTENDED, 1, { { 0, 9 } } },
+ { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$",
+ "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } },
+ { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$",
+ "ababababa", REG_EXTENDED, 1, { { 0, 9 } } },
+#endif
+};
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[5];
+ size_t i;
+ int n, ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ n = regcomp (&re, tests[i].pattern, tests[i].flags);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("%s: regcomp %zd failed: %s\n", tests[i].pattern, i, buf);
+ ret = 1;
+ continue;
+ }
+
+ if (regexec (&re, tests[i].string, tests[i].nmatch, rm, 0))
+ {
+ printf ("%s: regexec %zd failed\n", tests[i].pattern, i);
+ ret = 1;
+ regfree (&re);
+ continue;
+ }
+
+ for (n = 0; n < tests[i].nmatch; ++n)
+ if (rm[n].rm_so != tests[i].rm[n].rm_so
+ || rm[n].rm_eo != tests[i].rm[n].rm_eo)
+ {
+ if (tests[i].rm[n].rm_so == -1 && tests[i].rm[n].rm_eo == -1)
+ break;
+ printf ("%s: regexec %zd match failure rm[%d] %d..%d\n",
+ tests[i].pattern, i, n, rm[n].rm_so, rm[n].rm_eo);
+ ret = 1;
+ break;
+ }
+
+ regfree (&re);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex12.c b/libc/posix/bug-regex12.c
new file mode 100644
index 000000000..0ad063ea0
--- /dev/null
+++ b/libc/posix/bug-regex12.c
@@ -0,0 +1,73 @@
+/* Regular expression tests.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Tests supposed to not match. */
+struct
+{
+ const char *pattern;
+ const char *string;
+ int flags, nmatch;
+} tests[] = {
+ { "^<\\([^~]*\\)\\([^~]\\)[^~]*~\\1\\(.\\).*|=.*\\3.*\\2",
+ "<,.8~2,~so-|=-~.0,123456789<><", REG_NOSUB, 0 },
+ /* In ERE, all carets must be treated as anchors. */
+ { "a^b", "a^b", REG_EXTENDED, 0 }
+};
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[4];
+ size_t i;
+ int n, ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ n = regcomp (&re, tests[i].pattern, tests[i].flags);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp %zd failed: %s\n", i, buf);
+ ret = 1;
+ continue;
+ }
+
+ if (! regexec (&re, tests[i].string, tests[i].nmatch,
+ tests[i].nmatch ? rm : NULL, 0))
+ {
+ printf ("regexec %zd incorrectly matched\n", i);
+ ret = 1;
+ }
+
+ regfree (&re);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex13.c b/libc/posix/bug-regex13.c
new file mode 100644
index 000000000..df1c95d64
--- /dev/null
+++ b/libc/posix/bug-regex13.c
@@ -0,0 +1,103 @@
+/* Regular expression tests.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct
+{
+ int syntax;
+ const char *pattern;
+ const char *string;
+ int start;
+} tests[] = {
+ {RE_BACKSLASH_ESCAPE_IN_LISTS, "[0\\-9]", "1", -1}, /* It should not match. */
+ {RE_BACKSLASH_ESCAPE_IN_LISTS, "[0\\-9]", "-", 0}, /* It should match. */
+ {RE_SYNTAX_POSIX_BASIC, "s1\n.*\ns3", "s1\ns2\ns3", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}c", "abbc", -1},
+ /* Nested duplication. */
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{1}c", "ac", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{1}c", "abc", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{1}c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{2}{2}c", "ac", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{2}{2}c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{2}{2}c", "abbbbc", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{2}{2}c", "abbbbbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}{1}c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}{1}c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}{1}c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{0}c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{0}c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{1}{0}c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}*c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}*c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}*c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}?c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}?c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}?c", "abbc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}+c", "ac", 0},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}+c", "abc", -1},
+ {RE_SYNTAX_POSIX_EXTENDED, "ab{0}+c", "abbc", -1},
+};
+
+int
+main (void)
+{
+ struct re_pattern_buffer regbuf;
+ const char *err;
+ size_t i;
+ int ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ int start;
+ re_set_syntax (tests[i].syntax);
+ memset (&regbuf, '\0', sizeof (regbuf));
+ err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
+ &regbuf);
+ if (err != NULL)
+ {
+ printf ("re_compile_pattern failed: %s\n", err);
+ ret = 1;
+ continue;
+ }
+
+ start = re_search (&regbuf, tests[i].string, strlen (tests[i].string),
+ 0, strlen (tests[i].string), NULL);
+ if (start != tests[i].start)
+ {
+ printf ("re_search failed %d\n", start);
+ ret = 1;
+ regfree (&regbuf);
+ continue;
+ }
+ regfree (&regbuf);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex14.c b/libc/posix/bug-regex14.c
new file mode 100644
index 000000000..91ff32a74
--- /dev/null
+++ b/libc/posix/bug-regex14.c
@@ -0,0 +1,54 @@
+/* Tests re_comp and re_exec.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define _REGEX_RE_COMP
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ const char *err;
+ size_t i;
+ int ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < 100; ++i)
+ {
+ err = re_comp ("a t.st");
+ if (err)
+ {
+ printf ("re_comp failed: %s\n", err);
+ ret = 1;
+ }
+
+ if (! re_exec ("This is a test."))
+ {
+ printf ("re_exec failed\n");
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex15.c b/libc/posix/bug-regex15.c
new file mode 100644
index 000000000..8f6d3cc00
--- /dev/null
+++ b/libc/posix/bug-regex15.c
@@ -0,0 +1,32 @@
+/* Test for memory/CPU leak in regcomp. */
+
+#include <error.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_DATA_LIMIT (32 << 20)
+
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+static int
+do_test (void)
+{
+ regex_t re;
+ int reerr;
+
+ reerr = regcomp (&re, "^6?3?[25]?5?[14]*[25]*[69]*+[58]*87?4?$",
+ REG_EXTENDED | REG_NOSUB);
+ if (reerr != 0)
+ {
+ char buf[100];
+ regerror (reerr, &re, buf, sizeof buf);
+ printf ("regerror %s\n", buf);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/bug-regex16.c b/libc/posix/bug-regex16.c
new file mode 100644
index 000000000..1e41ccb71
--- /dev/null
+++ b/libc/posix/bug-regex16.c
@@ -0,0 +1,35 @@
+/* Test re_compile_pattern error messages. */
+
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+
+int
+main (void)
+{
+ struct re_pattern_buffer re;
+ const char *s;
+ int ret = 0;
+
+ re_set_syntax (RE_SYNTAX_POSIX_EGREP);
+ memset (&re, 0, sizeof (re));
+ s = re_compile_pattern ("[[.invalid_collating_symbol.]]", 30, &re);
+ if (s == NULL || strcmp (s, "Invalid collation character"))
+ {
+ printf ("re_compile_pattern returned %s\n", s);
+ ret = 1;
+ }
+ s = re_compile_pattern ("[[=invalid_equivalence_class=]]", 31, &re);
+ if (s == NULL || strcmp (s, "Invalid collation character"))
+ {
+ printf ("re_compile_pattern returned %s\n", s);
+ ret = 1;
+ }
+ s = re_compile_pattern ("[[:invalid_character_class:]]", 29, &re);
+ if (s == NULL || strcmp (s, "Invalid character class name"))
+ {
+ printf ("re_compile_pattern returned %s\n", s);
+ ret = 1;
+ }
+ return ret;
+}
diff --git a/libc/posix/bug-regex17.c b/libc/posix/bug-regex17.c
new file mode 100644
index 000000000..b42f9b6c1
--- /dev/null
+++ b/libc/posix/bug-regex17.c
@@ -0,0 +1,95 @@
+/* Turkish regular expression tests.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+/* Tests supposed to match. */
+struct
+{
+ const char *pattern;
+ const char *string;
+ int flags, nmatch;
+ regmatch_t rm[5];
+} tests[] = {
+ /* \xc3\x84 LATIN CAPITAL LETTER A WITH DIAERESIS
+ \xc3\x96 LATIN CAPITAL LETTER O WITH DIAERESIS
+ \xc3\xa4 LATIN SMALL LETTER A WITH DIAERESIS
+ \xc3\xb6 LATIN SMALL LETTER O WITH DIAERESIS */
+ { "\xc3\x84\xc3\x96*\xc3\xb6$", "aB\xc3\xa4\xc3\xb6\xc3\xb6\xc3\x96", REG_ICASE, 2,
+ { { 2, 10 }, { -1, -1 } } },
+ { "[\xc3\x84x]\xc3\x96*\xc3\xb6$", "aB\xc3\x84\xc3\xb6\xc3\xb6\xc3\x96", REG_ICASE, 2,
+ { { 2, 10 }, { -1, -1 } } },
+ { "[\xc3\x84x]\xc3\x96*\xc3\xb6$", "aB\xc3\xa4\xc3\xb6\xc3\xb6\xc3\x96", REG_ICASE, 2,
+ { { 2, 10 }, { -1, -1 } } },
+ { "[^x]\xc3\x96*\xc3\xb6$", "aB\xc3\xa4\xc3\xb6\xc3\xb6\xc3\x96", REG_ICASE, 2,
+ { { 2, 10 }, { -1, -1 } } },
+};
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[5];
+ size_t i;
+ int n, ret = 0;
+
+ setlocale (LC_ALL, "de_DE.UTF-8");
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ n = regcomp (&re, tests[i].pattern, tests[i].flags);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp %zd failed: %s\n", i, buf);
+ ret = 1;
+ continue;
+ }
+
+ if (regexec (&re, tests[i].string, tests[i].nmatch, rm, 0))
+ {
+ printf ("regexec %zd failed\n", i);
+ ret = 1;
+ regfree (&re);
+ continue;
+ }
+
+ for (n = 0; n < tests[i].nmatch; ++n)
+ if (rm[n].rm_so != tests[i].rm[n].rm_so
+ || rm[n].rm_eo != tests[i].rm[n].rm_eo)
+ {
+ if (tests[i].rm[n].rm_so == -1 && tests[i].rm[n].rm_eo == -1)
+ break;
+ printf ("regexec match failure rm[%d] %d..%d\n",
+ n, rm[n].rm_so, rm[n].rm_eo);
+ ret = 1;
+ break;
+ }
+
+ regfree (&re);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex18.c b/libc/posix/bug-regex18.c
new file mode 100644
index 000000000..a193ed921
--- /dev/null
+++ b/libc/posix/bug-regex18.c
@@ -0,0 +1,100 @@
+/* Turkish regular expression tests.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+/* Tests supposed to match. */
+struct
+{
+ const char *pattern;
+ const char *string;
+ int flags, nmatch;
+ regmatch_t rm[5];
+} tests[] = {
+ /* \xc4\xb0 LATIN CAPITAL LETTER I WITH DOT ABOVE
+ \xc4\xb1 LATIN SMALL LETTER DOTLESS I
+ \xe2\x80\x94 EM DASH */
+ { "\xc4\xb0I*\xc4\xb1$", "aBi\xc4\xb1\xc4\xb1I", REG_ICASE, 2,
+ { { 2, 8 }, { -1, -1 } } },
+ { "[\xc4\xb0x]I*\xc4\xb1$", "aBi\xc4\xb1\xc4\xb1I", REG_ICASE, 2,
+ { { 2, 8 }, { -1, -1 } } },
+ { "[^x]I*\xc4\xb1$", "aBi\xc4\xb1\xc4\xb1I", REG_ICASE, 2,
+ { { 2, 8 }, { -1, -1 } } },
+ { "([[:alpha:]]i[[:xdigit:]])(\xc4\xb1*)(\xc4\xb0{2})",
+ "\xe2\x80\x94\xc4\xb1\xc4\xb0""fIi\xc4\xb0ii", REG_ICASE | REG_EXTENDED,
+ 4, { { 3, 12 }, { 3, 8 }, { 8, 9 }, { 9, 12 } } },
+ { "\xc4\xb1i(i)*()(\\s\xc4\xb0|\\SI)", "SIi\xc4\xb0\xc4\xb0 is",
+ REG_ICASE | REG_EXTENDED, 4, { { 1, 9 }, { 5, 7 }, { 7, 7 }, { 7, 9 } } },
+ { "\xc4\xb1i(i)*()(\\s\xc4\xb0|\\SI)", "\xc4\xb1\xc4\xb0\xc4\xb0iJ\xc4\xb1",
+ REG_ICASE | REG_EXTENDED, 4,
+ { { 0, 10 }, { 6, 7 }, { 7, 7 }, { 7, 10 } } },
+};
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[5];
+ size_t i;
+ int n, ret = 0;
+
+ setlocale (LC_ALL, "tr_TR.UTF-8");
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ n = regcomp (&re, tests[i].pattern, tests[i].flags);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp %zd failed: %s\n", i, buf);
+ ret = 1;
+ continue;
+ }
+
+ if (regexec (&re, tests[i].string, tests[i].nmatch, rm, 0))
+ {
+ printf ("regexec %zd failed\n", i);
+ ret = 1;
+ regfree (&re);
+ continue;
+ }
+
+ for (n = 0; n < tests[i].nmatch; ++n)
+ if (rm[n].rm_so != tests[i].rm[n].rm_so
+ || rm[n].rm_eo != tests[i].rm[n].rm_eo)
+ {
+ if (tests[i].rm[n].rm_so == -1 && tests[i].rm[n].rm_eo == -1)
+ break;
+ printf ("regexec match failure rm[%d] %d..%d\n",
+ n, rm[n].rm_so, rm[n].rm_eo);
+ ret = 1;
+ break;
+ }
+
+ regfree (&re);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex19.c b/libc/posix/bug-regex19.c
new file mode 100644
index 000000000..3a173a6ca
--- /dev/null
+++ b/libc/posix/bug-regex19.c
@@ -0,0 +1,418 @@
+/* Regular expression tests.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+#define BRE RE_SYNTAX_POSIX_BASIC
+#define ERE RE_SYNTAX_POSIX_EXTENDED
+
+static struct test_s
+{
+ int syntax;
+ const char *pattern;
+ const char *string;
+ int start, res;
+} tests[] = {
+ {BRE, "\\<A", "CBAA", 0, -1},
+ {BRE, "\\<A", "CBAA", 2, -1},
+ {BRE, "A\\>", "CAAB", 1, -1},
+ {BRE, "\\bA", "CBAA", 0, -1},
+ {BRE, "\\bA", "CBAA", 2, -1},
+ {BRE, "A\\b", "CAAB", 1, -1},
+ {BRE, "\\<A", "AA", 0, 0},
+ {BRE, "\\<A", "C-AA", 2, 2},
+ {BRE, "A\\>", "CAA-", 1, 2},
+ {BRE, "A\\>", "CAA", 1, 2},
+ {BRE, "\\bA", "AA", 0, 0},
+ {BRE, "\\bA", "C-AA", 2, 2},
+ {BRE, "A\\b", "CAA-", 1, 2},
+ {BRE, "A\\b", "CAA", 1, 2},
+ {BRE, "\\<[A]", "CBAA", 0, -1},
+ {BRE, "\\<[A]", "CBAA", 2, -1},
+ {BRE, "[A]\\>", "CAAB", 1, -1},
+ {BRE, "\\b[A]", "CBAA", 0, -1},
+ {BRE, "\\b[A]", "CBAA", 2, -1},
+ {BRE, "[A]\\b", "CAAB", 1, -1},
+ {BRE, "\\<[A]", "AA", 0, 0},
+ {BRE, "\\<[A]", "C-AA", 2, 2},
+ {BRE, "[A]\\>", "CAA-", 1, 2},
+ {BRE, "[A]\\>", "CAA", 1, 2},
+ {BRE, "\\b[A]", "AA", 0, 0},
+ {BRE, "\\b[A]", "C-AA", 2, 2},
+ {BRE, "[A]\\b", "CAA-", 1, 2},
+ {BRE, "[A]\\b", "CAA", 1, 2},
+ {ERE, "\\b(A|!|.B)", "A=AC", 0, 0},
+ {ERE, "\\b(A|!|.B)", "=AC", 0, 1},
+ {ERE, "\\b(A|!|.B)", "!AC", 0, 1},
+ {ERE, "\\b(A|!|.B)", "=AB", 0, 1},
+ {ERE, "\\b(A|!|.B)", "DA!C", 0, 2},
+ {ERE, "\\b(A|!|.B)", "=CB", 0, 1},
+ {ERE, "\\b(A|!|.B)", "!CB", 0, 1},
+ {ERE, "\\b(A|!|.B)", "D,B", 0, 1},
+ {ERE, "\\b(A|!|.B)", "!.C", 0, -1},
+ {ERE, "\\b(A|!|.B)", "BCB", 0, -1},
+ {ERE, "(A|\\b)(A|B|C)", "DAAD", 0, 1},
+ {ERE, "(A|\\b)(A|B|C)", "DABD", 0, 1},
+ {ERE, "(A|\\b)(A|B|C)", "AD", 0, 0},
+ {ERE, "(A|\\b)(A|B|C)", "C!", 0, 0},
+ {ERE, "(A|\\b)(A|B|C)", "D,B", 0, 2},
+ {ERE, "(A|\\b)(A|B|C)", "DA?A", 0, 3},
+ {ERE, "(A|\\b)(A|B|C)", "BBC", 0, 0},
+ {ERE, "(A|\\b)(A|B|C)", "DA", 0, -1},
+ {ERE, "(!|\\b)(!|=|~)", "A!=\\", 0, 1},
+ {ERE, "(!|\\b)(!|=|~)", "/!=A", 0, 1},
+ {ERE, "(!|\\b)(!|=|~)", "A=A", 0, 1},
+ {ERE, "(!|\\b)(!|=|~)", "==!=", 0, 2},
+ {ERE, "(!|\\b)(!|=|~)", "==C~", 0, 3},
+ {ERE, "(!|\\b)(!|=|~)", "=~=", 0, -1},
+ {ERE, "(!|\\b)(!|=|~)", "~!", 0, -1},
+ {ERE, "(!|\\b)(!|=|~)", "~=~", 0, -1},
+ {ERE, "(\\b|A.)[ABC]", "AC", 0, 0},
+ {ERE, "(\\b|A.)[ABC]", "=A", 0, 1},
+ {ERE, "(\\b|A.)[ABC]", "DACC", 0, 1},
+ {ERE, "(\\b|A.)[A~C]", "AC", 0, 0},
+ {ERE, "(\\b|A.)[A~C]", "=A", 0, 1},
+ {ERE, "(\\b|A.)[A~C]", "DACC", 0, 1},
+ {ERE, "(\\b|A.)[A~C]", "B!A=", 0, 2},
+ {ERE, "(\\b|A.)[A~C]", "B~C", 0, 1},
+ {ERE, ".\\b.", "AA~", 0, 1},
+ {ERE, ".\\b.", "=A=", 0, 0},
+ {ERE, ".\\b.", "==", 0, -1},
+ {ERE, ".\\b.", "ABA", 0, -1},
+ {ERE, "[^k]\\b[^k]", "AA~", 0, 1},
+ {ERE, "[^k]\\b[^k]", "=A=", 0, 0},
+ {ERE, "[^k]\\b[^k]", "Ak~kA~", 0, 4},
+ {ERE, "[^k]\\b[^k]", "==", 0, -1},
+ {ERE, "[^k]\\b[^k]", "ABA", 0, -1},
+ {ERE, "[^k]\\b[^k]", "Ak~", 0, -1},
+ {ERE, "[^k]\\b[^k]", "k=k", 0, -1},
+ {ERE, "[^C]\\b[^C]", "AA~", 0, 1},
+ {ERE, "[^C]\\b[^C]", "=A=", 0, 0},
+ {ERE, "[^C]\\b[^C]", "AC~CA~", 0, 4},
+ {ERE, "[^C]\\b[^C]", "==", 0, -1},
+ {ERE, "[^C]\\b[^C]", "ABA", 0, -1},
+ {ERE, "[^C]\\b[^C]", "AC~", 0, -1},
+ {ERE, "[^C]\\b[^C]", "C=C", 0, -1},
+ {ERE, "\\<(A|!|.B)", "A=AC", 0, 0},
+ {ERE, "\\<(A|!|.B)", "=AC", 0, 1},
+ {ERE, "\\<(A|!|.B)", "!AC", 0, 1},
+ {ERE, "\\<(A|!|.B)", "=AB", 0, 1},
+ {ERE, "\\<(A|!|.B)", "=CB", 0, 1},
+ {ERE, "\\<(A|!|.B)", "!CB", 0, 1},
+ {ERE, "\\<(A|!|.B)", "DA!C", 0, -1},
+ {ERE, "\\<(A|!|.B)", "D,B", 0, -1},
+ {ERE, "\\<(A|!|.B)", "!.C", 0, -1},
+ {ERE, "\\<(A|!|.B)", "BCB", 0, -1},
+ {ERE, "(A|\\<)(A|B|C)", "DAAD", 0, 1},
+ {ERE, "(A|\\<)(A|B|C)", "DABD", 0, 1},
+ {ERE, "(A|\\<)(A|B|C)", "AD", 0, 0},
+ {ERE, "(A|\\<)(A|B|C)", "C!", 0, 0},
+ {ERE, "(A|\\<)(A|B|C)", "D,B", 0, 2},
+ {ERE, "(A|\\<)(A|B|C)", "DA?A", 0, 3},
+ {ERE, "(A|\\<)(A|B|C)", "BBC", 0, 0},
+ {ERE, "(A|\\<)(A|B|C)", "DA", 0, -1},
+ {ERE, "(!|\\<)(!|=|~)", "A!=\\", 0, 1},
+ {ERE, "(!|\\<)(!|=|~)", "/!=A", 0, 1},
+ {ERE, "(!|\\<)(!|=|~)", "==!=", 0, 2},
+ {ERE, "(!|\\<)(!|=|~)", "==C~", 0, -1},
+ {ERE, "(!|\\<)(!|=|~)", "A=A", 0, -1},
+ {ERE, "(!|\\<)(!|=|~)", "=~=", 0, -1},
+ {ERE, "(!|\\<)(!|=|~)", "~!", 0, -1},
+ {ERE, "(!|\\<)(!|=|~)", "~=~", 0, -1},
+ {ERE, "(\\<|A.)[ABC]", "AC", 0, 0},
+ {ERE, "(\\<|A.)[ABC]", "=A", 0, 1},
+ {ERE, "(\\<|A.)[ABC]", "DACC", 0, 1},
+ {ERE, "(\\<|A.)[A~C]", "AC", 0, 0},
+ {ERE, "(\\<|A.)[A~C]", "=A", 0, 1},
+ {ERE, "(\\<|A.)[A~C]", "DACC", 0, 1},
+ {ERE, "(\\<|A.)[A~C]", "B!A=", 0, 2},
+ {ERE, "(\\<|A.)[A~C]", "B~C", 0, 2},
+ {ERE, ".\\<.", "=A=", 0, 0},
+ {ERE, ".\\<.", "AA~", 0, -1},
+ {ERE, ".\\<.", "==", 0, -1},
+ {ERE, ".\\<.", "ABA", 0, -1},
+ {ERE, "[^k]\\<[^k]", "=k=A=", 0, 2},
+ {ERE, "[^k]\\<[^k]", "kk~", 0, -1},
+ {ERE, "[^k]\\<[^k]", "==", 0, -1},
+ {ERE, "[^k]\\<[^k]", "ABA", 0, -1},
+ {ERE, "[^k]\\<[^k]", "=k=", 0, -1},
+ {ERE, "[^C]\\<[^C]", "=C=A=", 0, 2},
+ {ERE, "[^C]\\<[^C]", "CC~", 0, -1},
+ {ERE, "[^C]\\<[^C]", "==", 0, -1},
+ {ERE, "[^C]\\<[^C]", "ABA", 0, -1},
+ {ERE, "[^C]\\<[^C]", "=C=", 0, -1},
+ {ERE, ".\\B.", "ABA", 0, 0},
+ {ERE, ".\\B.", "=BDC", 0, 1},
+ {ERE, "[^k]\\B[^k]", "kkkABA", 0, 3},
+ {ERE, "[^k]\\B[^k]", "kBk", 0, -1},
+ {ERE, "[^C]\\B[^C]", "CCCABA", 0, 3},
+ {ERE, "[^C]\\B[^C]", "CBC", 0, -1},
+ {ERE, ".(\\b|\\B).", "=~AB", 0, 0},
+ {ERE, ".(\\b|\\B).", "A=C", 0, 0},
+ {ERE, ".(\\b|\\B).", "ABC", 0, 0},
+ {ERE, ".(\\b|\\B).", "=~\\!", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "=~AB", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "A=C", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "ABC", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "=~kBD", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "=~\\!", 0, 0},
+ {ERE, "[^k](\\b|\\B)[^k]", "=~kB", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "=~AB", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "A=C", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "ABC", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "=~CBD", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "=~\\!", 0, 0},
+ {ERE, "[^C](\\b|\\B)[^C]", "=~CB", 0, 0},
+ {ERE, "\\b([A]|[!]|.B)", "A=AC", 0, 0},
+ {ERE, "\\b([A]|[!]|.B)", "=AC", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "!AC", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "=AB", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "DA!C", 0, 2},
+ {ERE, "\\b([A]|[!]|.B)", "=CB", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "!CB", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "D,B", 0, 1},
+ {ERE, "\\b([A]|[!]|.B)", "!.C", 0, -1},
+ {ERE, "\\b([A]|[!]|.B)", "BCB", 0, -1},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "DAAD", 0, 1},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "DABD", 0, 1},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "AD", 0, 0},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "C!", 0, 0},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "D,B", 0, 2},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "DA?A", 0, 3},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "BBC", 0, 0},
+ {ERE, "([A]|\\b)([A]|[B]|[C])", "DA", 0, -1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "A!=\\", 0, 1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "/!=A", 0, 1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "A=A", 0, 1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "==!=", 0, 2},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "==C~", 0, 3},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "=~=", 0, -1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "~!", 0, -1},
+ {ERE, "([!]|\\b)([!]|[=]|[~])", "~=~", 0, -1},
+ {ERE, "\\<([A]|[!]|.B)", "A=AC", 0, 0},
+ {ERE, "\\<([A]|[!]|.B)", "=AC", 0, 1},
+ {ERE, "\\<([A]|[!]|.B)", "!AC", 0, 1},
+ {ERE, "\\<([A]|[!]|.B)", "=AB", 0, 1},
+ {ERE, "\\<([A]|[!]|.B)", "=CB", 0, 1},
+ {ERE, "\\<([A]|[!]|.B)", "!CB", 0, 1},
+ {ERE, "\\<([A]|[!]|.B)", "DA!C", 0, -1},
+ {ERE, "\\<([A]|[!]|.B)", "D,B", 0, -1},
+ {ERE, "\\<([A]|[!]|.B)", "!.C", 0, -1},
+ {ERE, "\\<([A]|[!]|.B)", "BCB", 0, -1},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "DAAD", 0, 1},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "DABD", 0, 1},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "AD", 0, 0},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "C!", 0, 0},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "D,B", 0, 2},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "DA?A", 0, 3},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "BBC", 0, 0},
+ {ERE, "([A]|\\<)([A]|[B]|[C])", "DA", 0, -1},
+ {ERE, "([!]|\\<)([!=]|[~])", "A!=\\", 0, 1},
+ {ERE, "([!]|\\<)([!=]|[~])", "/!=A", 0, 1},
+ {ERE, "([!]|\\<)([!=]|[~])", "==!=", 0, 2},
+ {ERE, "([!]|\\<)([!=]|[~])", "==C~", 0, -1},
+ {ERE, "([!]|\\<)([!=]|[~])", "A=A", 0, -1},
+ {ERE, "([!]|\\<)([!=]|[~])", "=~=", 0, -1},
+ {ERE, "([!]|\\<)([!=]|[~])", "~!", 0, -1},
+ {ERE, "([!]|\\<)([!=]|[~])", "~=~", 0, -1},
+ {ERE, "(\\<|[A].)[ABC]", "AC", 0, 0},
+ {ERE, "(\\<|[A].)[ABC]", "=A", 0, 1},
+ {ERE, "(\\<|[A].)[ABC]", "DACC", 0, 1},
+ {ERE, "(\\<|[A].)[A~C]", "AC", 0, 0},
+ {ERE, "(\\<|[A].)[A~C]", "=A", 0, 1},
+ {ERE, "(\\<|[A].)[A~C]", "DACC", 0, 1},
+ {ERE, "(\\<|[A].)[A~C]", "B!A=", 0, 2},
+ {ERE, "(\\<|[A].)[A~C]", "B~C", 0, 2},
+ {ERE, "^[^A]*\\bB", "==B", 0, 0},
+ {ERE, "^[^A]*\\bB", "CBD!=B", 0, 0},
+ {ERE, "[^A]*\\bB", "==B", 2, 2}
+};
+
+int
+do_one_test (const struct test_s *test, const char *fail)
+{
+ int res;
+ const char *err;
+ struct re_pattern_buffer regbuf;
+
+ re_set_syntax (test->syntax);
+ memset (&regbuf, '\0', sizeof (regbuf));
+ err = re_compile_pattern (test->pattern, strlen (test->pattern),
+ &regbuf);
+ if (err != NULL)
+ {
+ printf ("%sre_compile_pattern \"%s\" failed: %s\n", fail, test->pattern,
+ err);
+ return 1;
+ }
+
+ res = re_search (&regbuf, test->string, strlen (test->string),
+ test->start, strlen (test->string) - test->start, NULL);
+ if (res != test->res)
+ {
+ printf ("%sre_search \"%s\" \"%s\" failed: %d (expected %d)\n",
+ fail, test->pattern, test->string, res, test->res);
+ regfree (&regbuf);
+ return 1;
+ }
+
+ if (test->res > 0 && test->start == 0)
+ {
+ res = re_search (&regbuf, test->string, strlen (test->string),
+ test->res, strlen (test->string) - test->res, NULL);
+ if (res != test->res)
+ {
+ printf ("%sre_search from expected \"%s\" \"%s\" failed: %d (expected %d)\n",
+ fail, test->pattern, test->string, res, test->res);
+ regfree (&regbuf);
+ return 1;
+ }
+ }
+
+ regfree (&regbuf);
+ return 0;
+}
+
+static char *
+replace (char *p, char c)
+{
+ switch (c)
+ {
+ /* A -> A" */
+ case 'A': *p++ = '\xc3'; *p++ = '\x84'; break;
+ /* B -> O" */
+ case 'B': *p++ = '\xc3'; *p++ = '\x96'; break;
+ /* C -> U" */
+ case 'C': *p++ = '\xc3'; *p++ = '\x9c'; break;
+ /* D -> a" */
+ case 'D': *p++ = '\xc3'; *p++ = '\xa4'; break;
+ /* ! -> MULTIPLICATION SIGN */
+ case '!': *p++ = '\xc3'; *p++ = '\x97'; break;
+ /* = -> EM DASH */
+ case '=': *p++ = '\xe2'; *p++ = '\x80'; *p++ = '\x94'; break;
+ /* ~ -> MUSICAL SYMBOL HALF NOTE */
+ case '~': *p++ = '\xf0'; *p++ = '\x9d'; *p++ = '\x85'; *p++ = '\x9e';
+ break;
+ }
+ return p;
+}
+
+int
+do_mb_tests (const struct test_s *test)
+{
+ int i, j;
+ struct test_s t;
+ const char *const chars = "ABCD!=~";
+ char repl[8], *p;
+ char pattern[strlen (test->pattern) * 4 + 1];
+ char string[strlen (test->string) * 4 + 1];
+ char fail[8 + sizeof ("UTF-8 ")];
+
+ t = *test;
+ t.pattern = pattern;
+ t.string = string;
+ strcpy (fail, "UTF-8 ");
+ for (i = 1; i < 128; ++i)
+ {
+ p = repl;
+ for (j = 0; j < 7; ++j)
+ if (i & (1 << j))
+ {
+ if (!strchr (test->pattern, chars[j])
+ && !strchr (test->string, chars[j]))
+ break;
+ *p++ = chars[j];
+ }
+ if (j < 7)
+ continue;
+ *p = '\0';
+
+ for (j = 0, p = pattern; test->pattern[j]; ++j)
+ if (strchr (repl, test->pattern[j]))
+ p = replace (p, test->pattern[j]);
+ else if (test->pattern[j] == '\\' && test->pattern[j + 1])
+ {
+ *p++ = test->pattern[j++];
+ *p++ = test->pattern[j];
+ }
+ else
+ *p++ = test->pattern[j];
+ *p = '\0';
+
+ t.start = test->start;
+ t.res = test->res;
+
+ for (j = 0, p = string; test->string[j]; ++j)
+ if (strchr (repl, test->string[j]))
+ {
+ char *d = replace (p, test->string[j]);
+ if (test->start > j)
+ t.start += d - p - 1;
+ if (test->res > j)
+ t.res += d - p - 1;
+ p = d;
+ }
+ else
+ *p++ = test->string[j];
+ *p = '\0';
+
+ p = stpcpy (fail + strlen ("UTF-8 "), repl);
+ *p++ = ' ';
+ *p = '\0';
+
+ if (do_one_test (&t, fail))
+ return 1;
+ }
+ return 0;
+}
+
+int
+main (void)
+{
+ size_t i;
+ int ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ if (setlocale (LC_ALL, "de_DE.ISO-8859-1") == NULL)
+ {
+ puts ("setlocale de_DE.ISO-8859-1 failed");
+ ret = 1;
+ }
+ ret |= do_one_test (&tests[i], "");
+ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+ {
+ puts ("setlocale de_DE.UTF-8 failed");
+ ret = 1;
+ }
+ ret |= do_one_test (&tests[i], "UTF-8 ");
+ ret |= do_mb_tests (&tests[i]);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex2.c b/libc/posix/bug-regex2.c
new file mode 100644
index 000000000..cd92892d8
--- /dev/null
+++ b/libc/posix/bug-regex2.c
@@ -0,0 +1,54 @@
+/* Test for memory handling in regex.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static const char text[] = "This is a test; this is a test";
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[2];
+ int n;
+
+ mtrace ();
+
+ n = regcomp (&re, "a test", REG_EXTENDED);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp failed: %s\n", buf);
+ exit (1);
+ }
+
+ for (n = 0; n < 20; ++n)
+ regexec (&re, text, 2, rm, 0);
+
+ regfree (&re);
+
+ return 0;
+}
diff --git a/libc/posix/bug-regex20.c b/libc/posix/bug-regex20.c
new file mode 100644
index 000000000..e55a06d27
--- /dev/null
+++ b/libc/posix/bug-regex20.c
@@ -0,0 +1,287 @@
+/* Test for UTF-8 regular expression optimizations.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+#define RE_NO_INTERNAL_PROTOTYPES 1
+#include "regex_internal.h"
+
+#define BRE RE_SYNTAX_POSIX_BASIC
+#define ERE RE_SYNTAX_POSIX_EXTENDED
+
+static struct
+{
+ int syntax;
+ const char *pattern;
+ const char *string;
+ int res, optimize;
+} tests[] = {
+ /* \xc3\x84 LATIN CAPITAL LETTER A WITH DIAERESIS
+ \xc3\x96 LATIN CAPITAL LETTER O WITH DIAERESIS
+ \xc3\xa4 LATIN SMALL LETTER A WITH DIAERESIS
+ \xc3\xb6 LATIN SMALL LETTER O WITH DIAERESIS
+ \xe2\x80\x94 EM DASH */
+ /* Should be optimized. */
+ {BRE, "foo", "b\xc3\xa4rfoob\xc3\xa4z", 4, 1},
+ {BRE, "b\xc3\xa4z", "b\xc3\xa4rfoob\xc3\xa4z", 7, 1},
+ {BRE, "b\xc3\xa4*z", "b\xc3\xa4rfoob\xc3\xa4z", 7, 1},
+ {BRE, "b\xc3\xa4*z", "b\xc3\xa4rfoobz", 7, 1},
+ {BRE, "b\xc3\xa4\\+z", "b\xc3\xa4rfoob\xc3\xa4\xc3\xa4z", 7, 1},
+ {BRE, "b\xc3\xa4\\?z", "b\xc3\xa4rfoob\xc3\xa4z", 7, 1},
+ {BRE, "b\xc3\xa4\\{1,2\\}z", "b\xc3\xa4rfoob\xc3\xa4z", 7, 1},
+ {BRE, "^x\\|xy*z$", "\xc3\xb6xyyz", 2, 1},
+ {BRE, "^x\\\\y\\{6\\}z\\+", "x\\yyyyyyzz\xc3\xb6", 0, 1},
+ {BRE, "^x\\\\y\\{2,36\\}z\\+", "x\\yzz\xc3\xb6", -1, 1},
+ {BRE, "^x\\\\y\\{,3\\}z\\+", "x\\yyyzz\xc3\xb6", 0, 1},
+ {BRE, "^x\\|x\xc3\xa4*z$", "\xc3\xb6x\xc3\xa4\xc3\xa4z", 2, 1},
+ {BRE, "^x\\\\\xc3\x84\\{6\\}z\\+",
+ "x\\\xc3\x84\xc3\x84\xc3\x84\xc3\x84\xc3\x84\xc3\x84zz\xc3\xb6", 0, 1},
+ {BRE, "^x\\\\\xc3\x84\\{2,36\\}z\\+", "x\\\xc3\x84zz\xc3\xb6", -1, 1},
+ {BRE, "^x\\\\\xc3\x84\\{,3\\}z\\+",
+ "x\\\xc3\x84\xc3\x84\xc3\x84zz\xc3\xb6", 0, 1},
+ {BRE, "x[C]y", "axCy", 1, 1},
+ {BRE, "x[ABC]y", "axCy", 1, 1},
+ {BRE, "\\`x\\|z\\'", "x\xe2\x80\x94", 0, 1},
+ {BRE, "\\(xy\\)z\\1a\\1", "\xe2\x80\x94xyzxyaxy\xc3\x84", 3, 1},
+ {BRE, "xy\\?z", "\xc3\x84xz\xc3\xb6", 2, 1},
+ {BRE, "\\`\xc3\x84\\|z\\'", "\xc3\x84\xe2\x80\x94", 0, 1},
+ {BRE, "\\(x\xc3\x84\\)z\\1\x61\\1",
+ "\xe2\x80\x94x\xc3\x84zx\xc3\x84\x61x\xc3\x84\xc3\x96", 3, 1},
+ {BRE, "x\xc3\x96\\?z", "\xc3\x84xz\xc3\xb6", 2, 1},
+ {BRE, "x.y", "ax\xe2\x80\x94yz", 1, 1},
+ {BRE, "x.*z", "\xc3\x84xz", 2, 1},
+ {BRE, "x.*z", "\xc3\x84x\xe2\x80\x94z", 2, 1},
+ {BRE, "x.*z", "\xc3\x84x\xe2\x80\x94y\xf1\x90\x80\x90z", 2, 1},
+ {BRE, "x.*z", "\xc3\x84x\xe2\x80\x94\xc3\x94\xf1\x90\x80\x90z", 2, 1},
+ {BRE, "x.\\?z", "axz", 1, 1},
+ {BRE, "x.\\?z", "axyz", 1, 1},
+ {BRE, "x.\\?z", "ax\xc3\x84z", 1, 1},
+ {BRE, "x.\\?z", "ax\xe2\x80\x94z", 1, 1},
+ {BRE, "x.\\?z", "ax\xf0\x9d\x80\x80z", 1, 1},
+ {BRE, "x.\\?z", "ax\xf9\x81\x82\x83\x84z", 1, 1},
+ {BRE, "x.\\?z", "ax\xfd\xbf\xbf\xbf\xbf\xbfz", 1, 1},
+ {BRE, ".", "y", 0, 1},
+ {BRE, ".", "\xc3\x84", 0, 1},
+ {BRE, ".", "\xe2\x80\x94", 0, 1},
+ {BRE, ".", "\xf0\x9d\x80\x80", 0, 1},
+ {BRE, ".", "\xf9\x81\x82\x83\x84", 0, 1},
+ {BRE, ".", "\xfd\xbf\xbf\xbf\xbf\xbf", 0, 1},
+ {BRE, "x.\\?z", "axyyz", -1, 1},
+ {BRE, "x.\\?z", "ax\xc3\x84\xc3\x96z", -1, 1},
+ {BRE, "x.\\?z", "ax\xe2\x80\x94\xc3\xa4z", -1, 1},
+ {BRE, "x.\\?z", "ax\xf0\x9d\x80\x80yz", -1, 1},
+ {BRE, "x.\\?z", "ax\xf9\x81\x82\x83\x84\xf0\x9d\x80\x81z", -1, 1},
+ {BRE, "x.\\?z", "ax\xfd\xbf\xbf\xbf\xbf\xbf\xc3\x96z", -1, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94xz", -1, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94xyz", 3, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94x\xc3\x84y\xe2\x80\x94z", 3, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94x\xe2\x80\x94z", 3, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94x\xf0\x9d\x80\x80\xc3\x84z", 3, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94x.~\xe2\x80\x94\xf9\x81\x82\x83\x84z", 3, 1},
+ {BRE, "x.\\+z", "\xe2\x80\x94x\xfd\xbf\xbf\xbf\xbf\xbfz", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94xz", -1, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x\xc3\x96y\xc3\xa4z", -1, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94xyz", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x\xc3\x84\xe2\x80\x94z", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x\xe2\x80\x94z", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x\xf0\x9d\x80\x80\xc3\x84z", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x~\xe2\x80\x94z", 3, 1},
+ {BRE, "x.\\{1,2\\}z", "\xe2\x80\x94x\xfd\xbf\xbf\xbf\xbf\xbfz", 3, 1},
+ {BRE, "x\\(.w\\|\xc3\x86\\)\\?z", "axz", 1, 1},
+ {BRE, "x\\(.w\\|\xc3\x86\\)\\?z", "ax\xfd\xbf\xbf\xbf\xbf\xbfwz", 1, 1},
+ {BRE, "x\\(.w\\|\xc3\x86\\)\\?z", "ax\xc3\x86z", 1, 1},
+ {BRE, "x\\(.w\\|\xc3\x86\\)\\?z", "ax\xe2\x80\x96wz", 1, 1},
+ {ERE, "foo", "b\xc3\xa4rfoob\xc3\xa4z", 4, 1},
+ {ERE, "^x|xy*z$", "\xc3\xb6xyyz", 2, 1},
+ {ERE, "^x\\\\y{6}z+", "x\\yyyyyyzz\xc3\xb6", 0, 1},
+ {ERE, "^x\\\\y{2,36}z+", "x\\yzz\xc3\xb6", -1, 1},
+ {ERE, "^x\\\\y{,3}z+", "x\\yyyzz\xc3\xb6", 0, 1},
+ {ERE, "x[C]y", "axCy", 1, 1},
+ {ERE, "x[ABC]y", "axCy", 1, 1},
+ {ERE, "\\`x|z\\'", "x\xe2\x80\x94", 0, 1},
+ {ERE, "(xy)z\\1a\\1", "\xe2\x80\x94xyzxyaxy\xc3\x84", 3, 1},
+ {ERE, "xy?z", "\xc3\x84xz\xc3\xb6", 2, 1},
+ {ERE, "x.y", "ax\xe2\x80\x94yz", 1, 1},
+ {ERE, "x.*z", "\xc3\x84xz", 2, 1},
+ {ERE, "x.*z", "\xc3\x84x\xe2\x80\x94z", 2, 1},
+ {ERE, "x.*z", "\xc3\x84x\xe2\x80\x94y\xf1\x90\x80\x90z", 2, 1},
+ {ERE, "x.*z", "\xc3\x84x\xe2\x80\x94\xc3\x94\xf1\x90\x80\x90z", 2, 1},
+ {ERE, "x.?z", "axz", 1, 1},
+ {ERE, "x.?z", "axyz", 1, 1},
+ {ERE, "x.?z", "ax\xc3\x84z", 1, 1},
+ {ERE, "x.?z", "ax\xe2\x80\x94z", 1, 1},
+ {ERE, "x.?z", "ax\xf0\x9d\x80\x80z", 1, 1},
+ {ERE, "x.?z", "ax\xf9\x81\x82\x83\x84z", 1, 1},
+ {ERE, "x.?z", "ax\xfd\xbf\xbf\xbf\xbf\xbfz", 1, 1},
+ {ERE, "x.?z", "axyyz", -1, 1},
+ {ERE, "x.?z", "ax\xc3\x84\xc3\x96z", -1, 1},
+ {ERE, "x.?z", "ax\xe2\x80\x94\xc3\xa4z", -1, 1},
+ {ERE, "x.?z", "ax\xf0\x9d\x80\x80yz", -1, 1},
+ {ERE, "x.?z", "ax\xf9\x81\x82\x83\x84\xf0\x9d\x80\x81z", -1, 1},
+ {ERE, "x.?z", "ax\xfd\xbf\xbf\xbf\xbf\xbf\xc3\x96z", -1, 1},
+ {ERE, "x.+z", "\xe2\x80\x94xz", -1, 1},
+ {ERE, "x.+z", "\xe2\x80\x94xyz", 3, 1},
+ {ERE, "x.+z", "\xe2\x80\x94x\xc3\x84y\xe2\x80\x94z", 3, 1},
+ {ERE, "x.+z", "\xe2\x80\x94x\xe2\x80\x94z", 3, 1},
+ {ERE, "x.+z", "\xe2\x80\x94x\xf0\x9d\x80\x80\xc3\x84z", 3, 1},
+ {ERE, "x.+z", "\xe2\x80\x94x.~\xe2\x80\x94\xf9\x81\x82\x83\x84z", 3, 1},
+ {ERE, "x.+z", "\xe2\x80\x94x\xfd\xbf\xbf\xbf\xbf\xbfz", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94xz", -1, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x\xc3\x96y\xc3\xa4z", -1, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94xyz", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x\xc3\x84\xe2\x80\x94z", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x\xe2\x80\x94z", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x\xf0\x9d\x80\x80\xc3\x84z", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x~\xe2\x80\x94z", 3, 1},
+ {ERE, "x.{1,2}z", "\xe2\x80\x94x\xfd\xbf\xbf\xbf\xbf\xbfz", 3, 1},
+ {ERE, "x(.w|\xc3\x86)?z", "axz", 1, 1},
+ {ERE, "x(.w|\xc3\x86)?z", "ax\xfd\xbf\xbf\xbf\xbf\xbfwz", 1, 1},
+ {ERE, "x(.w|\xc3\x86)?z", "ax\xc3\x86z", 1, 1},
+ {ERE, "x(.w|\xc3\x86)?z", "ax\xe2\x80\x96wz", 1, 1},
+ /* Should not be optimized. */
+ {BRE, "x[\xc3\x84\xc3\xa4]y", "ax\xc3\xa4y", 1, 0},
+ {BRE, "x[A-Z,]y", "axCy", 1, 0},
+ {BRE, "x[^y]z", "ax\xe2\x80\x94z", 1, 0},
+ {BRE, "x[[:alnum:]]z", "ax\xc3\x96z", 1, 0},
+ {BRE, "x[[=A=]]z", "axAz", 1, 0},
+ {BRE, "x[[=\xc3\x84=]]z", "ax\xc3\x84z", 1, 0},
+ {BRE, "\\<g", "\xe2\x80\x94g", 3, 0},
+ {BRE, "\\bg\\b", "\xe2\x80\x94g", 3, 0},
+ {BRE, "\\Bg\\B", "\xc3\xa4g\xc3\xa4", 2, 0},
+ {BRE, "a\\wz", "a\xc3\x84z", 0, 0},
+ {BRE, "x\\Wz", "\xc3\x96x\xe2\x80\x94z", 2, 0},
+ {ERE, "x[\xc3\x84\xc3\xa4]y", "ax\xc3\xa4y", 1, 0},
+ {ERE, "x[A-Z,]y", "axCy", 1, 0},
+ {ERE, "x[^y]z", "ax\xe2\x80\x94z", 1, 0},
+ {ERE, "x[[:alnum:]]z", "ax\xc3\x96z", 1, 0},
+ {ERE, "x[[=A=]]z", "axAz", 1, 0},
+ {ERE, "x[[=\xc3\x84=]]z", "ax\xc3\x84z", 1, 0},
+ {ERE, "\\<g", "\xe2\x80\x94g", 3, 0},
+ {ERE, "\\bg\\b", "\xe2\x80\x94g", 3, 0},
+ {ERE, "\\Bg\\B", "\xc3\xa4g\xc3\xa4", 2, 0},
+ {ERE, "a\\wz", "a\xc3\x84z", 0, 0},
+ {ERE, "x\\Wz", "\xc3\x96x\xe2\x80\x94z", 2, 0},
+};
+
+int
+main (void)
+{
+ struct re_pattern_buffer regbuf;
+ const char *err;
+ size_t i;
+ int ret = 0;
+
+ mtrace ();
+
+ setlocale (LC_ALL, "de_DE.UTF-8");
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+ int res, optimized;
+
+ re_set_syntax (tests[i].syntax);
+ memset (&regbuf, '\0', sizeof (regbuf));
+ err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
+ &regbuf);
+ if (err != NULL)
+ {
+ printf ("re_compile_pattern failed: %s\n", err);
+ ret = 1;
+ continue;
+ }
+
+ /* Check if re_search will be done as multi-byte or single-byte. */
+ optimized = ((re_dfa_t *) regbuf.buffer)->mb_cur_max == 1;
+ if (optimized != tests[i].optimize)
+ {
+ printf ("pattern %zd %soptimized while it should%s be\n",
+ i, optimized ? "" : "not ", tests[i].optimize ? "" : " not");
+ ret = 1;
+ }
+
+ int str_len = strlen (tests[i].string);
+ res = re_search (&regbuf, tests[i].string, str_len, 0, str_len, NULL);
+ if (res != tests[i].res)
+ {
+ printf ("re_search %zd failed: %d\n", i, res);
+ ret = 1;
+ regfree (&regbuf);
+ continue;
+ }
+
+ res = re_search (&regbuf, tests[i].string, str_len, str_len, -str_len,
+ NULL);
+ if (res != tests[i].res)
+ {
+ printf ("backward re_search %zd failed: %d\n", i, res);
+ ret = 1;
+ regfree (&regbuf);
+ continue;
+ }
+ regfree (&regbuf);
+
+ re_set_syntax (tests[i].syntax | RE_ICASE);
+ memset (&regbuf, '\0', sizeof (regbuf));
+ err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
+ &regbuf);
+ if (err != NULL)
+ {
+ printf ("re_compile_pattern failed: %s\n", err);
+ ret = 1;
+ continue;
+ }
+
+ /* Check if re_search will be done as multi-byte or single-byte. */
+ optimized = ((re_dfa_t *) regbuf.buffer)->mb_cur_max == 1;
+ if (optimized)
+ {
+ printf ("pattern %zd optimized while it should not be when case insensitive\n",
+ i);
+ ret = 1;
+ }
+
+ res = re_search (&regbuf, tests[i].string, str_len, 0, str_len, NULL);
+ if (res != tests[i].res)
+ {
+ printf ("ICASE re_search %zd failed: %d\n", i, res);
+ ret = 1;
+ regfree (&regbuf);
+ continue;
+ }
+
+ res = re_search (&regbuf, tests[i].string, str_len, str_len, -str_len,
+ NULL);
+ if (res != tests[i].res)
+ {
+ printf ("ICASE backward re_search %zd failed: %d\n", i, res);
+ ret = 1;
+ regfree (&regbuf);
+ continue;
+ }
+ regfree (&regbuf);
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex21.c b/libc/posix/bug-regex21.c
new file mode 100644
index 000000000..d67c4fe42
--- /dev/null
+++ b/libc/posix/bug-regex21.c
@@ -0,0 +1,45 @@
+/* Test for memory leaks in regcomp.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+
+int main (void)
+{
+ regex_t re;
+ int i;
+ int ret = 0;
+
+ mtrace ();
+
+ for (i = 0; i < 32; ++i)
+ {
+ if (regcomp (&re, "X-.+:.+Y=\".*\\.(A|B|C|D|E|F|G|H|I",
+ REG_EXTENDED | REG_ICASE) == 0)
+ {
+ puts ("regcomp unexpectedly succeeded");
+ ret = 1;
+ }
+ else
+ regfree (&re);
+ }
+ return ret;
+}
diff --git a/libc/posix/bug-regex22.c b/libc/posix/bug-regex22.c
new file mode 100644
index 000000000..c5bc94869
--- /dev/null
+++ b/libc/posix/bug-regex22.c
@@ -0,0 +1,119 @@
+/* Test re.translate != NULL.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <ctype.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+ struct re_pattern_buffer re;
+ char trans[256];
+ int i, result = 0;
+ const char *s;
+
+ setlocale (LC_ALL, "de_DE.ISO-8859-1");
+
+ for (i = 0; i < 256; ++i)
+ trans[i] = tolower (i);
+
+ re_set_syntax (RE_SYNTAX_POSIX_EGREP);
+
+ memset (&re, 0, sizeof (re));
+ re.translate = (unsigned char *) trans;
+ s = re_compile_pattern ("\\W", 2, &re);
+
+ if (s != NULL)
+ {
+ printf ("failed to compile pattern \"\\W\": %s\n", s);
+ result = 1;
+ }
+ else
+ {
+ int ret = re_search (&re, "abc.de", 6, 0, 6, NULL);
+ if (ret != 3)
+ {
+ printf ("1st re_search returned %d\n", ret);
+ result = 1;
+ }
+
+ ret = re_search (&re, "\xc4\xd6\xae\xf7", 4, 0, 4, NULL);
+ if (ret != 2)
+ {
+ printf ("2nd re_search returned %d\n", ret);
+ result = 1;
+ }
+ re.translate = NULL;
+ regfree (&re);
+ }
+
+ memset (&re, 0, sizeof (re));
+ re.translate = (unsigned char *) trans;
+ s = re_compile_pattern ("\\w", 2, &re);
+
+ if (s != NULL)
+ {
+ printf ("failed to compile pattern \"\\w\": %s\n", s);
+ result = 1;
+ }
+ else
+ {
+ int ret = re_search (&re, ".,!abc", 6, 0, 6, NULL);
+ if (ret != 3)
+ {
+ printf ("3rd re_search returned %d\n", ret);
+ result = 1;
+ }
+
+ ret = re_search (&re, "\xae\xf7\xc4\xd6", 4, 0, 4, NULL);
+ if (ret != 2)
+ {
+ printf ("4th re_search returned %d\n", ret);
+ result = 1;
+ }
+ re.translate = NULL;
+ regfree (&re);
+ }
+
+ memset (&re, 0, sizeof (re));
+ re.translate = (unsigned char *) trans;
+ s = re_compile_pattern ("[[:DIGIT:]]", 11, &re);
+ if (s == NULL)
+ {
+ printf ("compilation of \"[[:DIGIT:]]\" pattern unexpectedly succeeded: %s\n",
+ s);
+ result = 1;
+ }
+
+ memset (&re, 0, sizeof (re));
+ re.translate = (unsigned char *) trans;
+ s = re_compile_pattern ("[[:DIGIT:]]", 2, &re);
+ if (s == NULL)
+ {
+ printf ("compilation of \"[[:DIGIT:]]\" pattern unexpectedly succeeded: %s\n",
+ s);
+ result = 1;
+ }
+
+ return result;
+}
diff --git a/libc/posix/bug-regex23.c b/libc/posix/bug-regex23.c
new file mode 100644
index 000000000..61ee4f585
--- /dev/null
+++ b/libc/posix/bug-regex23.c
@@ -0,0 +1,35 @@
+/* Test we don't segfault on invalid UTF-8 sequence.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <regex.h>
+#include <string.h>
+
+int
+main (void)
+{
+ regex_t r;
+
+ memset (&r, 0, sizeof (r));
+ setlocale (LC_ALL, "de_DE.UTF-8");
+ regcomp (&r, "[-a-z_0-9.]+@[-a-z_0-9.]+", REG_EXTENDED | REG_ICASE);
+ regexec (&r, "\xe7\xb7\x95\xe7\x97", 0, NULL, 0);
+ return 0;
+}
diff --git a/libc/posix/bug-regex24.c b/libc/posix/bug-regex24.c
new file mode 100644
index 000000000..97c5c3508
--- /dev/null
+++ b/libc/posix/bug-regex24.c
@@ -0,0 +1,60 @@
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+
+#define str "civic"
+
+#define N 10
+static const char *expected[N] =
+ {
+ str, "c", "i", "", "", "", "", "", "", ""
+ };
+
+static int
+do_test (void)
+{
+ regex_t rbuf;
+ static const char pat[] = "\
+^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$";
+
+ int err = regcomp (&rbuf, pat, REG_EXTENDED);
+ if (err != 0)
+ {
+ char errstr[300];
+ regerror (err, &rbuf, errstr, sizeof (errstr));
+ puts (errstr);
+ return err;
+ }
+
+ regmatch_t m[N];
+ err = regexec (&rbuf, str, N, m, 0);
+ if (err != 0)
+ {
+ puts ("regexec failed");
+ return 1;
+ }
+
+ int result = 0;
+ for (int i = 0; i < N; ++i)
+ if (m[i].rm_so == -1)
+ {
+ printf ("m[%d] unused\n", i);
+ result = 1;
+ }
+ else
+ {
+ int len = m[i].rm_eo - m[i].rm_so;
+
+ printf ("m[%d] = \"%.*s\"\n", i, len, str + m[i].rm_so);
+
+ if (strlen (expected[i]) != len
+ || memcmp (expected[i], str + m[i].rm_so, len) != 0)
+ result = 1;
+ }
+
+ return result;
+}
+
+#define TIMEOUT 30
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/bug-regex25.c b/libc/posix/bug-regex25.c
new file mode 100644
index 000000000..5e56e49bb
--- /dev/null
+++ b/libc/posix/bug-regex25.c
@@ -0,0 +1,57 @@
+/* Test re_search in multibyte locale other than UTF-8.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *str1 = "\xa3\xd8\xa3\xc9\xa3\xc9";
+const char *str2 = "\xa3\xd8\xa3\xc9";
+
+int
+main (void)
+{
+ setlocale (LC_ALL, "ja_JP.eucJP");
+
+ re_set_syntax (RE_SYNTAX_SED);
+
+ struct re_pattern_buffer re;
+ memset (&re, 0, sizeof (re));
+
+ struct re_registers regs;
+ memset (&regs, 0, sizeof (regs));
+
+ re_compile_pattern ("$", 1, &re);
+
+ int ret = 0, r = re_search (&re, str1, 4, 0, 4, &regs);
+ if (r != 4)
+ {
+ printf ("First re_search returned %d\n", r);
+ ret = 1;
+ }
+ r = re_search (&re, str2, 4, 0, 4, &regs);
+ if (r != 4)
+ {
+ printf ("Second re_search returned %d\n", r);
+ ret = 1;
+ }
+ return ret;
+}
diff --git a/libc/posix/bug-regex3.c b/libc/posix/bug-regex3.c
new file mode 100644
index 000000000..bfbd38fd1
--- /dev/null
+++ b/libc/posix/bug-regex3.c
@@ -0,0 +1,45 @@
+/* Test for case handling in regex.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int
+main (void)
+{
+ regex_t re;
+ int n;
+
+ n = regcomp (&re, "[a-bA-B]", REG_ICASE);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp failed: %s\n", buf);
+ exit (1);
+ }
+
+ regfree (&re);
+
+ return 0;
+}
diff --git a/libc/posix/bug-regex4.c b/libc/posix/bug-regex4.c
new file mode 100644
index 000000000..0bac3ec51
--- /dev/null
+++ b/libc/posix/bug-regex4.c
@@ -0,0 +1,60 @@
+/* Test for re_search_2.
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+
+int
+main (void)
+{
+ struct re_pattern_buffer regex;
+ const char *s;
+ int match[3];
+ int result = 0;
+
+ memset (&regex, '\0', sizeof (regex));
+
+ setlocale (LC_ALL, "C");
+
+ s = re_compile_pattern ("ab[cde]", 7, &regex);
+ if (s != NULL)
+ {
+ puts ("re_compile_pattern returned non-NULL value");
+ result = 1;
+ }
+ else
+ {
+ match[0] = re_search_2 (&regex, "xyabez", 6, "", 0, 1, 5, NULL, 6);
+ match[1] = re_search_2 (&regex, NULL, 0, "abc", 3, 0, 3, NULL, 3);
+ match[2] = re_search_2 (&regex, "xya", 3, "bd", 2, 2, 3, NULL, 5);
+ if (match[0] != 2 || match[1] != 0 || match[2] != 2)
+ {
+ printf ("re_search_2 returned %d,%d,%d, expected 2,0,2\n",
+ match[0], match[1], match[2]);
+ result = 1;
+ }
+ else
+ puts (" -> OK");
+ }
+
+ return result;
+}
diff --git a/libc/posix/bug-regex5.c b/libc/posix/bug-regex5.c
new file mode 100644
index 000000000..f199ffbfd
--- /dev/null
+++ b/libc/posix/bug-regex5.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <locale/localeinfo.h>
+
+int
+main (void)
+{
+ int32_t table_size, idx, i, found;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+ uint32_t nrules;
+ char *ca;
+ union locale_data_value u;
+
+ ca = setlocale (LC_ALL, "da_DK.ISO-8859-1");
+ if (ca == NULL)
+ {
+ printf ("cannot set locale: %m\n");
+ return 1;
+ }
+ printf ("current locale : %s\n", ca);
+
+ u.string = nl_langinfo (_NL_COLLATE_NRULES);
+ nrules = u.word;
+ if (nrules == 0)
+ {
+ printf("No rule\n");
+ return 1;
+ }
+
+ u.string = nl_langinfo (_NL_COLLATE_SYMB_HASH_SIZEMB);
+ table_size = u.word;
+ symb_table = (const int32_t *) nl_langinfo (_NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *) nl_langinfo (_NL_COLLATE_SYMB_EXTRAMB);
+
+ found = 0;
+ for (i = 0; i < table_size; ++i)
+ {
+ if (symb_table[2 * i] != 0)
+ {
+ char elem[256];
+ idx = symb_table[2 * i + 1];
+ strncpy (elem, (const char *) (extra + idx + 1), extra[idx]);
+ elem[extra[idx]] = '\0';
+ printf ("Found a collating element: %s\n", elem);
+ ++found;
+ }
+ }
+ if (found == 0)
+ {
+ printf ("No collating element!\n");
+ return 1;
+ }
+ else if (found != 4)
+ {
+ printf ("expected 4 collating elements, found %d\n", found);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/bug-regex6.c b/libc/posix/bug-regex6.c
new file mode 100644
index 000000000..9c3f3750d
--- /dev/null
+++ b/libc/posix/bug-regex6.c
@@ -0,0 +1,76 @@
+/* Test for regexec.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+
+int
+main (int argc, char *argv[])
+{
+ regex_t re;
+ regmatch_t mat[10];
+ int i, j, ret = 0;
+ const char *locales[] = { "C", "de_DE.UTF-8" };
+ const char *string = "http://www.regex.com/pattern/matching.html#intro";
+ regmatch_t expect[10] = {
+ { 0, 48 }, { 0, 5 }, { 0, 4 }, { 5, 20 }, { 7, 20 }, { 20, 42 },
+ { -1, -1 }, { -1, -1 }, { 42, 48 }, { 43, 48 } };
+
+ for (i = 0; i < sizeof (locales) / sizeof (locales[0]); ++i)
+ {
+ if (setlocale (LC_ALL, locales[i]) == NULL)
+ {
+ puts ("cannot set locale");
+ ret = 1;
+ }
+ else if (regcomp (&re,
+ "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?",
+ REG_EXTENDED) != REG_NOERROR)
+ {
+ puts ("cannot compile the regular expression");
+ ret = 1;
+ }
+ else if (regexec (&re, string, 10, mat, 0) == REG_NOMATCH)
+ {
+ puts ("no match");
+ ret = 1;
+ }
+ else
+ {
+ if (! memcmp (mat, expect, sizeof (mat)))
+ printf ("matching ok for %s locale\n", locales[i]);
+ else
+ {
+ printf ("matching failed for %s locale:\n", locales[i]);
+ ret = 1;
+ for (j = 0; j < 9; ++j)
+ if (mat[j].rm_so != -1)
+ printf ("%d: %.*s\n", j, mat[j].rm_eo - mat[j].rm_so,
+ string + mat[j].rm_so);
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/libc/posix/bug-regex7.c b/libc/posix/bug-regex7.c
new file mode 100644
index 000000000..44594597d
--- /dev/null
+++ b/libc/posix/bug-regex7.c
@@ -0,0 +1,92 @@
+/* Test for regs allocation in re_search and re_match.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Stepan Kasal <kasal@math.cas.cz>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+
+int
+main (void)
+{
+ struct re_pattern_buffer regex;
+ struct re_registers regs;
+ const char *s;
+ int match, n;
+ int result = 0;
+
+ memset (&regex, '\0', sizeof (regex));
+ regs.start = regs.end = NULL;
+ regs.num_regs = 0;
+ s = re_compile_pattern ("a", 1, &regex);
+ if (s != NULL)
+ {
+ puts ("failed to compile pattern \"a\"");
+ result = 1;
+ }
+ else
+ {
+ match = re_search (&regex, "baobab", 6, 0, 6, &regs);
+ n = 1;
+ if (match != 1)
+ {
+ printf ("re_search returned %d, expected 1\n", match);
+ result = 1;
+ }
+ else if (regs.num_regs <= n || regs.start[n] != -1 || regs.end[n] != -1)
+ {
+ puts ("re_search failed to fill the -1 sentinel");
+ result = 1;
+ }
+ }
+
+ free (regex.buffer);
+ memset (&regex, '\0', sizeof (regex));
+
+ s = re_compile_pattern ("\\(\\(\\(a\\)\\)\\)", 13, &regex);
+ if (s != NULL)
+ {
+ puts ("failed to compile pattern /\\(\\(\\(a\\)\\)\\)/");
+ result = 1;
+ }
+ else
+ {
+ match = re_match (&regex, "apl", 3, 0, &regs);
+ n = 4;
+ if (match != 1)
+ {
+ printf ("re_match returned %d, expected 1\n", match);
+ result = 1;
+ }
+ else if (regs.num_regs <= n || regs.start[n] != -1 || regs.end[n] != -1)
+ {
+ puts ("re_match failed to fill the -1 sentinel");
+ result = 1;
+ }
+ }
+
+ if (result == 0)
+ puts (" -> OK");
+
+ return result;
+}
diff --git a/libc/posix/bug-regex8.c b/libc/posix/bug-regex8.c
new file mode 100644
index 000000000..8383e0150
--- /dev/null
+++ b/libc/posix/bug-regex8.c
@@ -0,0 +1,84 @@
+/* Test for the STOP parameter of re_match_2 and re_search_2.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Stepan Kasal <kasal@math.cas.cz>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+
+int
+main (void)
+{
+ struct re_pattern_buffer regex;
+ const char *s;
+ int match[4];
+
+ memset (&regex, '\0', sizeof (regex));
+
+ s = re_compile_pattern ("xy$", 3, &regex);
+ if (s != NULL)
+ {
+ puts ("failed to compile pattern \"xy$\"");
+ return 1;
+ }
+ else
+ match[0] = re_match_2(&regex,"xyz",3,NULL,0,0,NULL,2);
+
+ free (regex.buffer);
+ memset (&regex, '\0', sizeof (regex));
+
+ s = re_compile_pattern ("xy\\>", 4, &regex);
+ if (s != NULL)
+ {
+ puts ("failed to compile pattern \"xy\\>\"");
+ return 1;
+ }
+ else
+ match[1] = re_search_2(&regex,"xyz",3,NULL,0,0,2,NULL,2);
+
+ free (regex.buffer);
+ memset (&regex, '\0', sizeof (regex));
+
+ s = re_compile_pattern ("xy \\<", 5, &regex);
+ if (s != NULL)
+ {
+ puts ("failed to compile pattern \"xy \\<\"");
+ return 1;
+ }
+ else
+ {
+ match[2] = re_match_2(&regex,"xy ",4,NULL,0,0,NULL,3);
+ match[3] = re_match_2(&regex,"xy z",4,NULL,0,0,NULL,3);
+ }
+
+ if (match[0] != -1 || match[1] != -1 || match[2] != -1 || match[3] != 3)
+ {
+ printf ("re_{match,search}_2 returned %d,%d,%d,%d, expected -1,-1,-1,3\n",
+ match[0], match[1], match[2], match[3]);
+ return 1;
+ }
+
+ puts (" -> OK");
+
+ return 0;
+}
diff --git a/libc/posix/bug-regex9.c b/libc/posix/bug-regex9.c
new file mode 100644
index 000000000..5a32668ae
--- /dev/null
+++ b/libc/posix/bug-regex9.c
@@ -0,0 +1,67 @@
+/* Test for memory handling in regex.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static const char text[] = "#! /bin/sh";
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t rm[2];
+ int n;
+
+ mtrace ();
+
+ n = regcomp (&re, "^#! */.*/(k|ba||pdk|z)sh", REG_EXTENDED);
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("regcomp failed: %s\n", buf);
+ exit (1);
+ }
+
+ for (n = 0; n < 20; ++n)
+ {
+ if (regexec (&re, text, 2, rm, 0))
+ {
+ puts ("regexec failed");
+ exit (2);
+ }
+ if (rm[0].rm_so != 0 || rm[0].rm_eo != 10
+ || rm[1].rm_so != 8 || rm[1].rm_eo != 8)
+ {
+ printf ("regexec match failure: %d %d %d %d\n",
+ rm[0].rm_so, rm[0].rm_eo, rm[1].rm_so, rm[1].rm_eo);
+ exit (3);
+ }
+ }
+
+ regfree (&re);
+
+ return 0;
+}
diff --git a/libc/posix/confstr.c b/libc/posix/confstr.c
new file mode 100644
index 000000000..26b0fa875
--- /dev/null
+++ b/libc/posix/confstr.c
@@ -0,0 +1,280 @@
+/* Copyright (C) 1991, 1996, 1997, 2000-2002, 2003, 2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <confstr.h>
+#include "../version.h"
+
+/* If BUF is not NULL and LEN > 0, fill in at most LEN - 1 bytes
+ of BUF with the value corresponding to NAME and zero-terminate BUF.
+ Return the number of bytes required to hold NAME's entire value. */
+size_t
+confstr (name, buf, len)
+ int name;
+ char *buf;
+ size_t len;
+{
+ const char *string = "";
+ size_t string_len = 1;
+
+ switch (name)
+ {
+ case _CS_PATH:
+ {
+ static const char cs_path[] = CS_PATH;
+ string = cs_path;
+ string_len = sizeof (cs_path);
+ }
+ break;
+
+ case _CS_V6_WIDTH_RESTRICTED_ENVS:
+ /* We have to return a newline-separated list of named of
+ programming environements in which the widths of blksize_t,
+ cc_t, mode_t, nfds_t, pid_t, ptrdiff_t, size_t, speed_t,
+ ssize_t, suseconds_t, tcflag_t, useconds_t, wchar_t, and
+ wint_t types are no greater than the width of type long.
+
+ Currently this means all environment which the system allows. */
+ {
+ char restenvs[4 * sizeof "POSIX_V6_LPBIG_OFFBIG"];
+
+ string_len = 0;
+#ifndef _POSIX_V6_ILP32_OFF32
+ if (__sysconf (_SC_V6_ILP32_OFF32) > 0)
+#endif
+#if !defined _POSIX_V6_ILP32_OFF32 || _POSIX_V6_ILP32_OFF32 > 0
+ {
+ memcpy (restenvs + string_len, "POSIX_V6_ILP32_OFF32",
+ sizeof "POSIX_V6_ILP32_OFF32" - 1);
+ string_len += sizeof "POSIX_V6_ILP32_OFF32" - 1;
+ }
+#endif
+#ifndef _POSIX_V6_ILP32_OFFBIG
+ if (__sysconf (_SC_V6_ILP32_OFFBIG) > 0)
+#endif
+#if !defined _POSIX_V6_ILP32_OFFBIG || _POSIX_V6_ILP32_OFFBIG > 0
+ {
+ if (string_len)
+ restenvs[string_len++] = '\n';
+ memcpy (restenvs + string_len, "POSIX_V6_ILP32_OFFBIG",
+ sizeof "POSIX_V6_ILP32_OFFBIG" - 1);
+ string_len += sizeof "POSIX_V6_ILP32_OFFBIG" - 1;
+ }
+#endif
+#ifndef _POSIX_V6_LP64_OFF64
+ if (__sysconf (_SC_V6_LP64_OFF64) > 0)
+#endif
+#if !defined _POSIX_V6_LP64_OFF64 || _POSIX_V6_LP64_OFF64 > 0
+ {
+ if (string_len)
+ restenvs[string_len++] = '\n';
+ memcpy (restenvs + string_len, "POSIX_V6_LP64_OFF64",
+ sizeof "POSIX_V6_LP64_OFF64" - 1);
+ string_len += sizeof "POSIX_V6_LP64_OFF64" - 1;
+ }
+#endif
+#ifndef _POSIX_V6_LPBIG_OFFBIG
+ if (__sysconf (_SC_V6_LPBIG_OFFBIG) > 0)
+#endif
+#if !defined _POSIX_V6_LPBIG_OFFBIG || _POSIX_V6_LPBIG_OFFBIG > 0
+ {
+ if (string_len)
+ restenvs[string_len++] = '\n';
+ memcpy (restenvs + string_len, "POSIX_V6_LPBIG_OFFBIG",
+ sizeof "POSIX_V6_LPBIG_OFFBIG" - 1);
+ string_len += sizeof "POSIX_V6_LPBIG_OFFBIG" - 1;
+ }
+#endif
+ restenvs[string_len++] = '\0';
+ string = restenvs;
+ }
+ break;
+
+ case _CS_XBS5_ILP32_OFF32_CFLAGS:
+ case _CS_POSIX_V6_ILP32_OFF32_CFLAGS:
+#ifdef __ILP32_OFF32_CFLAGS
+# if _POSIX_V6_ILP32_OFF32 == -1
+# error "__ILP32_OFF32_CFLAGS should not be defined"
+# elif !defined _POSIX_V6_ILP32_OFF32
+ if (__sysconf (_SC_V6_ILP32_OFF32) < 0)
+ break;
+# endif
+ string = __ILP32_OFF32_CFLAGS;
+ string_len = sizeof (__ILP32_OFF32_CFLAGS);
+#endif
+ break;
+
+ case _CS_XBS5_ILP32_OFFBIG_CFLAGS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS:
+#ifdef __ILP32_OFFBIG_CFLAGS
+# if _POSIX_V6_ILP32_OFFBIG == -1
+# error "__ILP32_OFFBIG_CFLAGS should not be defined"
+# elif !defined _POSIX_V6_ILP32_OFFBIG
+ if (__sysconf (_SC_V6_ILP32_OFFBIG) < 0)
+ break;
+# endif
+ string = __ILP32_OFFBIG_CFLAGS;
+ string_len = sizeof (__ILP32_OFFBIG_CFLAGS);
+#endif
+ break;
+
+ case _CS_XBS5_LP64_OFF64_CFLAGS:
+ case _CS_POSIX_V6_LP64_OFF64_CFLAGS:
+#ifdef __LP64_OFF64_CFLAGS
+# if _POSIX_V6_LP64_OFF64 == -1
+# error "__LP64_OFF64_CFLAGS should not be defined"
+# elif !defined _POSIX_V6_LP64_OFF64
+ if (__sysconf (_SC_V6_LP64_OFF64) < 0)
+ break;
+# endif
+ string = __LP64_OFF64_CFLAGS;
+ string_len = sizeof (__LP64_OFF64_CFLAGS);
+#endif
+ break;
+
+ case _CS_XBS5_ILP32_OFF32_LDFLAGS:
+ case _CS_POSIX_V6_ILP32_OFF32_LDFLAGS:
+#ifdef __ILP32_OFF32_LDFLAGS
+# if _POSIX_V6_ILP32_OFF32 == -1
+# error "__ILP32_OFF32_LDFLAGS should not be defined"
+# elif !defined _POSIX_V6_ILP32_OFF32
+ if (__sysconf (_SC_V6_ILP32_OFF32) < 0)
+ break;
+# endif
+ string = __ILP32_OFF32_LDFLAGS;
+ string_len = sizeof (__ILP32_OFF32_LDFLAGS);
+#endif
+ break;
+
+ case _CS_XBS5_ILP32_OFFBIG_LDFLAGS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS:
+#ifdef __ILP32_OFFBIG_LDFLAGS
+# if _POSIX_V6_ILP32_OFFBIG == -1
+# error "__ILP32_OFFBIG_LDFLAGS should not be defined"
+# elif !defined _POSIX_V6_ILP32_OFFBIG
+ if (__sysconf (_SC_V6_ILP32_OFFBIG) < 0)
+ break;
+# endif
+ string = __ILP32_OFFBIG_LDFLAGS;
+ string_len = sizeof (__ILP32_OFFBIG_LDFLAGS);
+#endif
+ break;
+
+ case _CS_XBS5_LP64_OFF64_LDFLAGS:
+ case _CS_POSIX_V6_LP64_OFF64_LDFLAGS:
+#ifdef __LP64_OFF64_LDFLAGS
+# if _POSIX_V6_LP64_OFF64 == -1
+# error "__LP64_OFF64_LDFLAGS should not be defined"
+# elif !defined _POSIX_V6_LP64_OFF64
+ if (__sysconf (_SC_V6_LP64_OFF64) < 0)
+ break;
+# endif
+ string = __LP64_OFF64_LDFLAGS;
+ string_len = sizeof (__LP64_OFF64_LDFLAGS);
+#endif
+ break;
+
+ case _CS_LFS_CFLAGS:
+ case _CS_LFS_LINTFLAGS:
+#if _POSIX_V6_ILP32_OFF32 == 1 && _POSIX_V6_ILP32_OFFBIG == 1
+# define __LFS_CFLAGS "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ /* Signal that we want the new ABI. */
+ string = __LFS_CFLAGS;
+ string_len = sizeof (__LFS_CFLAGS);
+#endif
+ break;
+
+ case _CS_LFS_LDFLAGS:
+ case _CS_LFS_LIBS:
+ /* No special libraries or linker flags needed. */
+ break;
+
+ case _CS_LFS64_CFLAGS:
+ case _CS_LFS64_LINTFLAGS:
+#define __LFS64_CFLAGS "-D_LARGEFILE64_SOURCE"
+ string = __LFS64_CFLAGS;
+ string_len = sizeof (__LFS64_CFLAGS);
+ break;
+
+ case _CS_LFS64_LDFLAGS:
+ case _CS_LFS64_LIBS:
+ /* No special libraries or linker flags needed. */
+ break;
+
+ case _CS_XBS5_ILP32_OFF32_LIBS:
+ case _CS_XBS5_ILP32_OFF32_LINTFLAGS:
+ case _CS_XBS5_ILP32_OFFBIG_LIBS:
+ case _CS_XBS5_ILP32_OFFBIG_LINTFLAGS:
+ case _CS_XBS5_LP64_OFF64_LIBS:
+ case _CS_XBS5_LP64_OFF64_LINTFLAGS:
+ case _CS_XBS5_LPBIG_OFFBIG_CFLAGS:
+ case _CS_XBS5_LPBIG_OFFBIG_LDFLAGS:
+ case _CS_XBS5_LPBIG_OFFBIG_LIBS:
+ case _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS:
+
+ case _CS_POSIX_V6_ILP32_OFF32_LIBS:
+ case _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_LIBS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS:
+ case _CS_POSIX_V6_LP64_OFF64_LIBS:
+ case _CS_POSIX_V6_LP64_OFF64_LINTFLAGS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_LIBS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS:
+ /* GNU libc does not require special actions to use LFS functions. */
+ break;
+
+ case _CS_GNU_LIBC_VERSION:
+ string = "glibc " VERSION;
+ string_len = sizeof ("glibc " VERSION);
+ break;
+
+ case _CS_GNU_LIBPTHREAD_VERSION:
+#ifdef LIBPTHREAD_VERSION
+ string = LIBPTHREAD_VERSION;
+ string_len = sizeof LIBPTHREAD_VERSION;
+ break;
+#else
+ /* No thread library. */
+ __set_errno (EINVAL);
+ return 0;
+#endif
+
+ default:
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ if (len > 0 && buf != NULL)
+ {
+ if (string_len <= len)
+ memcpy (buf, string, string_len);
+ else
+ {
+ memcpy (buf, string, len - 1);
+ buf[len - 1] = '\0';
+ }
+ }
+ return string_len;
+}
+libc_hidden_def (confstr)
diff --git a/libc/posix/cpio.h b/libc/posix/cpio.h
new file mode 100644
index 000000000..fae32752a
--- /dev/null
+++ b/libc/posix/cpio.h
@@ -0,0 +1,74 @@
+/* Extended cpio format from POSIX.1.
+ This file is part of the GNU C Library.
+ Copyright (C) 1992, 1998 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU cpio.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _CPIO_H
+#define _CPIO_H 1
+
+/* A cpio archive consists of a sequence of files.
+ Each file has a 76 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of octal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 must be "070707"
+ c_dev 6
+ c_ino 6
+ c_mode 6 see below for value
+ c_uid 6
+ c_gid 6
+ c_nlink 6
+ c_rdev 6 only valid for chr and blk special files
+ c_mtime 11
+ c_namesize 6 count includes terminating NUL in pathname
+ c_filesize 11 must be 0 for FIFOs and directories */
+
+/* Value for the field `c_magic'. */
+#define MAGIC "070707"
+
+/* Values for c_mode, OR'd together: */
+
+#define C_IRUSR 000400
+#define C_IWUSR 000200
+#define C_IXUSR 000100
+#define C_IRGRP 000040
+#define C_IWGRP 000020
+#define C_IXGRP 000010
+#define C_IROTH 000004
+#define C_IWOTH 000002
+#define C_IXOTH 000001
+
+#define C_ISUID 004000
+#define C_ISGID 002000
+#define C_ISVTX 001000
+
+#define C_ISBLK 060000
+#define C_ISCHR 020000
+#define C_ISDIR 040000
+#define C_ISFIFO 010000
+#define C_ISSOCK 0140000
+#define C_ISLNK 0120000
+#define C_ISCTG 0110000
+#define C_ISREG 0100000
+
+#endif /* cpio.h */
diff --git a/libc/posix/environ.c b/libc/posix/environ.c
new file mode 100644
index 000000000..a0ed0d80e
--- /dev/null
+++ b/libc/posix/environ.c
@@ -0,0 +1,12 @@
+/* This file just defines the `__environ' variable (and alias `environ'). */
+
+#include <unistd.h>
+#include <stddef.h>
+
+/* This must be initialized; we cannot have a weak alias into bss. */
+char **__environ = NULL;
+weak_alias (__environ, environ)
+
+/* The SVR4 ABI says `_environ' will be the name to use
+ in case the user overrides the weak alias `environ'. */
+weak_alias (__environ, _environ)
diff --git a/libc/posix/execl.c b/libc/posix/execl.c
new file mode 100644
index 000000000..7f822d014
--- /dev/null
+++ b/libc/posix/execl.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1991,92,94,97,98,99,2002,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stackinfo.h>
+
+
+/* Execute PATH with all arguments after PATH until
+ a NULL pointer and environment from `environ'. */
+int
+execl (const char *path, const char *arg, ...)
+{
+#define INITIAL_ARGV_MAX 1024
+ size_t argv_max = INITIAL_ARGV_MAX;
+ const char *initial_argv[INITIAL_ARGV_MAX];
+ const char **argv = initial_argv;
+ va_list args;
+
+ argv[0] = arg;
+
+ va_start (args, arg);
+ unsigned int i = 0;
+ while (argv[i++] != NULL)
+ {
+ if (i == argv_max)
+ {
+ argv_max *= 2;
+ const char **nptr = realloc (argv == initial_argv ? NULL : argv,
+ argv_max * sizeof (const char *));
+ if (nptr == NULL)
+ {
+ if (argv != initial_argv)
+ free (argv);
+ return -1;
+ }
+ if (argv == initial_argv)
+ /* We have to copy the already filled-in data ourselves. */
+ memcpy (nptr, argv, i * sizeof (const char *));
+
+ argv = nptr;
+ }
+
+ argv[i] = va_arg (args, const char *);
+ }
+ va_end (args);
+
+ int ret = __execve (path, (char *const *) argv, __environ);
+ if (argv != initial_argv)
+ free (argv);
+
+ return ret;
+}
+libc_hidden_def (execl)
diff --git a/libc/posix/execle.c b/libc/posix/execle.c
new file mode 100644
index 000000000..70522ad2e
--- /dev/null
+++ b/libc/posix/execle.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1991,97,98,99,2002,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stackinfo.h>
+
+/* Execute PATH with all arguments after PATH until a NULL pointer,
+ and the argument after that for environment. */
+int
+execle (const char *path, const char *arg, ...)
+{
+#define INITIAL_ARGV_MAX 1024
+ size_t argv_max = INITIAL_ARGV_MAX;
+ const char *initial_argv[INITIAL_ARGV_MAX];
+ const char **argv = initial_argv;
+ va_list args;
+ argv[0] = arg;
+
+ va_start (args, arg);
+ unsigned int i = 0;
+ while (argv[i++] != NULL)
+ {
+ if (i == argv_max)
+ {
+ argv_max *= 2;
+ const char **nptr = realloc (argv == initial_argv ? NULL : argv,
+ argv_max * sizeof (const char *));
+ if (nptr == NULL)
+ {
+ if (argv != initial_argv)
+ free (argv);
+ return -1;
+ }
+ if (argv == initial_argv)
+ /* We have to copy the already filled-in data ourselves. */
+ memcpy (nptr, argv, i * sizeof (const char *));
+
+ argv = nptr;
+ }
+
+ argv[i] = va_arg (args, const char *);
+ }
+
+ const char *const *envp = va_arg (args, const char *const *);
+ va_end (args);
+
+ int ret = __execve (path, (char *const *) argv, (char *const *) envp);
+ if (argv != initial_argv)
+ free (argv);
+
+ return ret;
+}
+libc_hidden_def (execle)
diff --git a/libc/posix/execlp.c b/libc/posix/execlp.c
new file mode 100644
index 000000000..66996a936
--- /dev/null
+++ b/libc/posix/execlp.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1991,93,96,97,98,99,2002,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stackinfo.h>
+
+/* Execute FILE, searching in the `PATH' environment variable if
+ it contains no slashes, with all arguments after FILE until a
+ NULL pointer and environment from `environ'. */
+int
+execlp (const char *file, const char *arg, ...)
+{
+#define INITIAL_ARGV_MAX 1024
+ size_t argv_max = INITIAL_ARGV_MAX;
+ const char *initial_argv[INITIAL_ARGV_MAX];
+ const char **argv = initial_argv;
+ va_list args;
+
+ argv[0] = arg;
+
+ va_start (args, arg);
+ unsigned int i = 0;
+ while (argv[i++] != NULL)
+ {
+ if (i == argv_max)
+ {
+ argv_max *= 2;
+ const char **nptr = realloc (argv == initial_argv ? NULL : argv,
+ argv_max * sizeof (const char *));
+ if (nptr == NULL)
+ {
+ if (argv != initial_argv)
+ free (argv);
+ return -1;
+ }
+ if (argv == initial_argv)
+ /* We have to copy the already filled-in data ourselves. */
+ memcpy (nptr, argv, i * sizeof (const char *));
+
+ argv = nptr;
+ }
+
+ argv[i] = va_arg (args, const char *);
+ }
+ va_end (args);
+
+ int ret = execvp (file, (char *const *) argv);
+ if (argv != initial_argv)
+ free (argv);
+
+ return ret;
+}
+libc_hidden_def (execlp)
diff --git a/libc/posix/execv.c b/libc/posix/execv.c
new file mode 100644
index 000000000..cb372abe3
--- /dev/null
+++ b/libc/posix/execv.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991, 1992, 1997, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+
+
+/* Execute PATH with arguments ARGV and environment from `environ'. */
+int
+execv (const char *path, char *const argv[])
+{
+ return __execve (path, argv, __environ);
+}
diff --git a/libc/posix/execve.c b/libc/posix/execve.c
new file mode 100644
index 000000000..2d756293e
--- /dev/null
+++ b/libc/posix/execve.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Replace the current process, executing PATH with arguments ARGV and
+ environment ENVP. ARGV and ENVP are terminated by NULL pointers. */
+int
+__execve (path, argv, envp)
+ const char *path;
+ char *const argv[];
+ char *const envp[];
+{
+ if (path == NULL || argv == NULL || envp == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (execve)
+
+weak_alias (__execve, execve)
+#include <stub-tag.h>
diff --git a/libc/posix/execvp.c b/libc/posix/execvp.c
new file mode 100644
index 000000000..8421bd048
--- /dev/null
+++ b/libc/posix/execvp.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 1991,92,1995-99,2002,2004,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <paths.h>
+
+
+/* The file is accessible but it is not an executable file. Invoke
+ the shell to interpret it as a script. */
+static char **
+internal_function
+allocate_scripts_argv (const char *file, char *const argv[])
+{
+ /* Count the arguments. */
+ int argc = 0;
+ while (argv[argc++])
+ ;
+
+ /* Construct an argument list for the shell. */
+ char **new_argv = (char **) malloc ((argc + 1) * sizeof (char *));
+ if (new_argv != NULL)
+ {
+ new_argv[0] = (char *) _PATH_BSHELL;
+ new_argv[1] = (char *) file;
+ while (argc > 1)
+ {
+ new_argv[argc] = argv[argc - 1];
+ --argc;
+ }
+ }
+
+ return new_argv;
+}
+
+
+/* Execute FILE, searching in the `PATH' environment variable if it contains
+ no slashes, with arguments ARGV and environment from `environ'. */
+int
+execvp (file, argv)
+ const char *file;
+ char *const argv[];
+{
+ if (*file == '\0')
+ {
+ /* We check the simple case first. */
+ __set_errno (ENOENT);
+ return -1;
+ }
+
+ char **script_argv = NULL;
+
+ if (strchr (file, '/') != NULL)
+ {
+ /* Don't search when it contains a slash. */
+ __execve (file, argv, __environ);
+
+ if (errno == ENOEXEC)
+ {
+ script_argv = allocate_scripts_argv (file, argv);
+ if (script_argv != NULL)
+ {
+ __execve (script_argv[0], script_argv, __environ);
+
+ free (script_argv);
+ }
+ }
+ }
+ else
+ {
+ char *path = getenv ("PATH");
+ char *path_malloc = NULL;
+ if (path == NULL)
+ {
+ /* There is no `PATH' in the environment.
+ The default search path is the current directory
+ followed by the path `confstr' returns for `_CS_PATH'. */
+ size_t len = confstr (_CS_PATH, (char *) NULL, 0);
+ path = (char *) malloc (1 + len);
+ if (path == NULL)
+ return -1;
+ path[0] = ':';
+ (void) confstr (_CS_PATH, path + 1, len);
+ path_malloc = path;
+ }
+
+ size_t len = strlen (file) + 1;
+ size_t pathlen = strlen (path);
+ char *name = malloc (pathlen + len + 1);
+ if (name == NULL)
+ {
+ free (path_malloc);
+ return -1;
+ }
+ /* Copy the file name at the top. */
+ name = (char *) memcpy (name + pathlen + 1, file, len);
+ /* And add the slash. */
+ *--name = '/';
+
+ bool got_eacces = false;
+ char *p = path;
+ do
+ {
+ char *startp;
+
+ path = p;
+ p = __strchrnul (path, ':');
+
+ if (p == path)
+ /* Two adjacent colons, or a colon at the beginning or the end
+ of `PATH' means to search the current directory. */
+ startp = name + 1;
+ else
+ startp = (char *) memcpy (name - (p - path), path, p - path);
+
+ /* Try to execute this name. If it works, execve will not return. */
+ __execve (startp, argv, __environ);
+
+ if (errno == ENOEXEC)
+ {
+ if (script_argv == NULL)
+ {
+ script_argv = allocate_scripts_argv (startp, argv);
+ if (script_argv == NULL)
+ {
+ /* A possible EACCES error is not as important as
+ the ENOMEM. */
+ got_eacces = false;
+ break;
+ }
+ }
+
+ __execve (script_argv[0], script_argv, __environ);
+ }
+
+ switch (errno)
+ {
+ case EACCES:
+ /* Record the we got a `Permission denied' error. If we end
+ up finding no executable we can use, we want to diagnose
+ that we did find one but were denied access. */
+ got_eacces = true;
+ case ENOENT:
+ case ESTALE:
+ case ENOTDIR:
+ /* Those errors indicate the file is missing or not executable
+ by us, in which case we want to just try the next path
+ directory. */
+ case ENODEV:
+ case ETIMEDOUT:
+ /* Some strange filesystems like AFS return even
+ stranger error numbers. They cannot reasonably mean
+ anything else so ignore those, too. */
+ break;
+
+ default:
+ /* Some other error means we found an executable file, but
+ something went wrong executing it; return the error to our
+ caller. */
+ return -1;
+ }
+ }
+ while (*p++ != '\0');
+
+ /* We tried every element and none of them worked. */
+ if (got_eacces)
+ /* At least one failure was due to permissions, so report that
+ error. */
+ __set_errno (EACCES);
+
+ free (script_argv);
+ free (name - pathlen);
+ free (path_malloc);
+ }
+
+ /* Return the error from the last attempt (probably ENOENT). */
+ return -1;
+}
+libc_hidden_def (execvp)
diff --git a/libc/posix/fexecve.c b/libc/posix/fexecve.c
new file mode 100644
index 000000000..fceae9251
--- /dev/null
+++ b/libc/posix/fexecve.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Execute the file FD refers to, overlaying the running program image.
+ ARGV and ENVP are passed to the new program, as for `execve'. */
+int
+fexecve (fd, argv, envp)
+ int fd;
+ char *const argv[];
+ char *const envp[];
+{
+ if (fd < 0 || argv == NULL || envp == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (fexecve)
+#include <stub-tag.h>
diff --git a/libc/posix/fnmatch.c b/libc/posix/fnmatch.c
new file mode 100644
index 000000000..3fa7c322d
--- /dev/null
+++ b/libc/posix/fnmatch.c
@@ -0,0 +1,418 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Enable GNU extensions in fnmatch.h. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+#if HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+/* For platform which support the ISO C amendement 1 functionality we
+ support user defined character classes. */
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+/* We need some of the locale data (the collation sequence information)
+ but there is no interface to get this information in general. Therefore
+ we support a correct implementation only in glibc. */
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# include "../locale/elem-hash.h"
+# include "../locale/coll-lookup.h"
+# include <shlib-compat.h>
+
+# define CONCAT(a,b) __CONCAT(a,b)
+# define mbsrtowcs __mbsrtowcs
+# define fnmatch __fnmatch
+extern int fnmatch (const char *pattern, const char *string, int flags);
+#endif
+
+/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
+#define NO_LEADING_PERIOD(flags) \
+ ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined _LIBC || !defined __GNU_LIBRARY__
+
+
+# if defined STDC_HEADERS || !defined isascii
+# define ISASCII(c) 1
+# else
+# define ISASCII(c) isascii(c)
+# endif
+
+# ifdef isblank
+# define ISBLANK(c) (ISASCII (c) && isblank (c))
+# else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+# endif
+# ifdef isgraph
+# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+# else
+# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+# endif
+
+# define ISPRINT(c) (ISASCII (c) && isprint (c))
+# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+# define ISALNUM(c) (ISASCII (c) && isalnum (c))
+# define ISALPHA(c) (ISASCII (c) && isalpha (c))
+# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+# define ISLOWER(c) (ISASCII (c) && islower (c))
+# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+# define ISSPACE(c) (ISASCII (c) && isspace (c))
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* The GNU C library provides support for user-defined character classes
+ and the functions from ISO C amendement 1. */
+# ifdef CHARCLASS_NAME_MAX
+# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+# else
+/* This shouldn't happen but some implementation might still have this
+ problem. Use a reasonable default value. */
+# define CHAR_CLASS_MAX_LENGTH 256
+# endif
+
+# ifdef _LIBC
+# define IS_CHAR_CLASS(string) __wctype (string)
+# else
+# define IS_CHAR_CLASS(string) wctype (string)
+# endif
+
+# ifdef _LIBC
+# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
+# else
+# define ISWCTYPE(WC, WT) iswctype (WC, WT)
+# endif
+
+# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
+/* In this case we are implementing the multibyte character handling. */
+# define HANDLE_MULTIBYTE 1
+# endif
+
+# else
+# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
+
+# define IS_CHAR_CLASS(string) \
+ (STREQ (string, "alpha") || STREQ (string, "upper") \
+ || STREQ (string, "lower") || STREQ (string, "digit") \
+ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
+ || STREQ (string, "space") || STREQ (string, "print") \
+ || STREQ (string, "punct") || STREQ (string, "graph") \
+ || STREQ (string, "cntrl") || STREQ (string, "blank"))
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+# if !defined _LIBC && !defined getenv
+extern char *getenv ();
+# endif
+
+# ifndef errno
+extern int errno;
+# endif
+
+/* Global variable. */
+static int posixly_correct;
+
+/* This function doesn't exist on most systems. */
+
+# if !defined HAVE___STRCHRNUL && !defined _LIBC
+static char *
+__strchrnul (s, c)
+ const char *s;
+ int c;
+{
+ char *result = strchr (s, c);
+ if (result == NULL)
+ result = strchr (s, '\0');
+ return result;
+}
+# endif
+
+# if HANDLE_MULTIBYTE && !defined HAVE___STRCHRNUL && !defined _LIBC
+static wchar_t *
+__wcschrnul (s, c)
+ const wchar_t *s;
+ wint_t c;
+{
+ wchar_t *result = wcschr (s, c);
+ if (result == NULL)
+ result = wcschr (s, '\0');
+ return result;
+}
+# endif
+
+# ifndef internal_function
+/* Inside GNU libc we mark some function in a special way. In other
+ environments simply ignore the marking. */
+# define internal_function
+# endif
+
+/* Note that this evaluates C many times. */
+# ifdef _LIBC
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
+# else
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+# endif
+# define CHAR char
+# define UCHAR unsigned char
+# define INT int
+# define FCT internal_fnmatch
+# define EXT ext_match
+# define END end_pattern
+# define L(CS) CS
+# ifdef _LIBC
+# define BTOWC(C) __btowc (C)
+# else
+# define BTOWC(C) btowc (C)
+# endif
+# define STRLEN(S) strlen (S)
+# define STRCAT(D, S) strcat (D, S)
+# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
+# define MEMCHR(S, C, N) memchr (S, C, N)
+# define STRCOLL(S1, S2) strcoll (S1, S2)
+# include "fnmatch_loop.c"
+
+
+# if HANDLE_MULTIBYTE
+/* Note that this evaluates C many times. */
+# ifdef _LIBC
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
+# else
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? towlower (c) : (c))
+# endif
+# define CHAR wchar_t
+# define UCHAR wint_t
+# define INT wint_t
+# define FCT internal_fnwmatch
+# define EXT ext_wmatch
+# define END end_wpattern
+# define L(CS) L##CS
+# define BTOWC(C) (C)
+# define STRLEN(S) __wcslen (S)
+# define STRCAT(D, S) __wcscat (D, S)
+# define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
+# define MEMCHR(S, C, N) wmemchr (S, C, N)
+# define STRCOLL(S1, S2) wcscoll (S1, S2)
+# define WIDE_CHAR_VERSION 1
+
+# undef IS_CHAR_CLASS
+/* We have to convert the wide character string in a multibyte string. But
+ we know that the character class names consist of alphanumeric characters
+ from the portable character set, and since the wide character encoding
+ for a member of the portable character set is the same code point as
+ its single-byte encoding, we can use a simplified method to convert the
+ string to a multibyte character string. */
+static wctype_t
+is_char_class (const wchar_t *wcs)
+{
+ char s[CHAR_CLASS_MAX_LENGTH + 1];
+ char *cp = s;
+
+ do
+ {
+ /* Test for a printable character from the portable character set. */
+# ifdef _LIBC
+ if (*wcs < 0x20 || *wcs > 0x7e
+ || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
+ return (wctype_t) 0;
+# else
+ switch (*wcs)
+ {
+ case L' ': case L'!': case L'"': case L'#': case L'%':
+ case L'&': case L'\'': case L'(': case L')': case L'*':
+ case L'+': case L',': case L'-': case L'.': case L'/':
+ case L'0': case L'1': case L'2': case L'3': case L'4':
+ case L'5': case L'6': case L'7': case L'8': case L'9':
+ case L':': case L';': case L'<': case L'=': case L'>':
+ case L'?':
+ case L'A': case L'B': case L'C': case L'D': case L'E':
+ case L'F': case L'G': case L'H': case L'I': case L'J':
+ case L'K': case L'L': case L'M': case L'N': case L'O':
+ case L'P': case L'Q': case L'R': case L'S': case L'T':
+ case L'U': case L'V': case L'W': case L'X': case L'Y':
+ case L'Z':
+ case L'[': case L'\\': case L']': case L'^': case L'_':
+ case L'a': case L'b': case L'c': case L'd': case L'e':
+ case L'f': case L'g': case L'h': case L'i': case L'j':
+ case L'k': case L'l': case L'm': case L'n': case L'o':
+ case L'p': case L'q': case L'r': case L's': case L't':
+ case L'u': case L'v': case L'w': case L'x': case L'y':
+ case L'z': case L'{': case L'|': case L'}': case L'~':
+ break;
+ default:
+ return (wctype_t) 0;
+ }
+# endif
+
+ /* Avoid overrunning the buffer. */
+ if (cp == s + CHAR_CLASS_MAX_LENGTH)
+ return (wctype_t) 0;
+
+ *cp++ = (char) *wcs++;
+ }
+ while (*wcs != L'\0');
+
+ *cp = '\0';
+
+# ifdef _LIBC
+ return __wctype (s);
+# else
+ return wctype (s);
+# endif
+}
+# define IS_CHAR_CLASS(string) is_char_class (string)
+
+# include "fnmatch_loop.c"
+# endif
+
+
+int
+fnmatch (pattern, string, flags)
+ const char *pattern;
+ const char *string;
+ int flags;
+{
+# if HANDLE_MULTIBYTE
+ if (__builtin_expect (MB_CUR_MAX, 1) != 1)
+ {
+ mbstate_t ps;
+ size_t n;
+ const char *p;
+ wchar_t *wpattern;
+ wchar_t *wstring;
+
+ /* Convert the strings into wide characters. */
+ memset (&ps, '\0', sizeof (ps));
+ p = pattern;
+#ifdef _LIBC
+ n = strnlen (pattern, 1024);
+#else
+ n = strlen (pattern);
+#endif
+ if (__builtin_expect (n < 1024, 1))
+ {
+ wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ n = mbsrtowcs (wpattern, &p, n + 1, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ if (p)
+ memset (&ps, '\0', sizeof (ps));
+ }
+ if (__builtin_expect (p != NULL, 0))
+ {
+ n = mbsrtowcs (NULL, &pattern, 0, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ assert (mbsinit (&ps));
+ (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
+ }
+
+ assert (mbsinit (&ps));
+#ifdef _LIBC
+ n = strnlen (string, 1024);
+#else
+ n = strlen (string);
+#endif
+ p = string;
+ if (__builtin_expect (n < 1024, 1))
+ {
+ wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ n = mbsrtowcs (wstring, &p, n + 1, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ if (p)
+ memset (&ps, '\0', sizeof (ps));
+ }
+ if (__builtin_expect (p != NULL, 0))
+ {
+ n = mbsrtowcs (NULL, &string, 0, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ assert (mbsinit (&ps));
+ (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+ }
+
+ return internal_fnwmatch (wpattern, wstring, wstring + n,
+ flags & FNM_PERIOD, flags);
+ }
+# endif /* mbstate_t and mbsrtowcs or _LIBC. */
+
+ return internal_fnmatch (pattern, string, string + strlen (string),
+ flags & FNM_PERIOD, flags);
+}
+
+# ifdef _LIBC
+# undef fnmatch
+versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
+strong_alias (__fnmatch, __fnmatch_old)
+compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
+# endif
+libc_hidden_ver (__fnmatch, fnmatch)
+# endif
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/libc/posix/fnmatch.h b/libc/posix/fnmatch.h
new file mode 100644
index 000000000..aefb007fb
--- /dev/null
+++ b/libc/posix/fnmatch.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1991-93,96,97,98,99,2001,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _FNMATCH_H
+#define _FNMATCH_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef const
+# if (defined __STDC__ && __STDC__) || defined __cplusplus
+# define __const const
+# else
+# define __const
+# endif
+#endif
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
+# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+# define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+
+/* This value is returned if the implementation does not support
+ `fnmatch'. Since this is not the case here it will never be
+ returned but the conformance test suites still require the symbol
+ to be defined. */
+#ifdef _XOPEN_SOURCE
+# define FNM_NOSYS (-1)
+#endif
+
+/* Match NAME against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch (__const char *__pattern, __const char *__name,
+ int __flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/libc/posix/fnmatch_loop.c b/libc/posix/fnmatch_loop.c
new file mode 100644
index 000000000..02a4e9030
--- /dev/null
+++ b/libc/posix/fnmatch_loop.c
@@ -0,0 +1,1207 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2003,2004,2005
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+static int FCT (const CHAR *pattern, const CHAR *string,
+ const CHAR *string_end, int no_leading_period, int flags)
+ internal_function;
+static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
+ const CHAR *string_end, int no_leading_period, int flags)
+ internal_function;
+static const CHAR *END (const CHAR *patternp) internal_function;
+
+static int
+internal_function
+FCT (pattern, string, string_end, no_leading_period, flags)
+ const CHAR *pattern;
+ const CHAR *string;
+ const CHAR *string_end;
+ int no_leading_period;
+ int flags;
+{
+ register const CHAR *p = pattern, *n = string;
+ register UCHAR c;
+#ifdef _LIBC
+# if WIDE_CHAR_VERSION
+ const char *collseq = (const char *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+# else
+ const UCHAR *collseq = (const UCHAR *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+# endif
+#endif
+
+ while ((c = *p++) != L('\0'))
+ {
+ int new_no_leading_period = 0;
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case L('?'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+ else if (*n == L('/') && (flags & FNM_FILE_NAME))
+ return FNM_NOMATCH;
+ else if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+ break;
+
+ case L('\\'):
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ if (c == L('\0'))
+ /* Trailing \ loses. */
+ return FNM_NOMATCH;
+ c = FOLD (c);
+ }
+ if (n == string_end || FOLD ((UCHAR) *n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case L('*'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n != string_end && *n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == L('?') || c == L('*'); c = *p++)
+ {
+ if (*p == L('(') && (flags & FNM_EXTMATCH) != 0)
+ {
+ const CHAR *endp = END (p);
+ if (endp != p)
+ {
+ /* This is a pattern. Skip over it. */
+ p = endp;
+ continue;
+ }
+ }
+
+ if (c == L('?'))
+ {
+ /* A ? needs to match one character. */
+ if (n == string_end)
+ /* There isn't another character; no match. */
+ return FNM_NOMATCH;
+ else if (*n == L('/')
+ && __builtin_expect (flags & FNM_FILE_NAME, 0))
+ /* A slash does not match a wildcard under
+ FNM_FILE_NAME. */
+ return FNM_NOMATCH;
+ else
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ less than three characters. */
+ ++n;
+ }
+ }
+
+ if (c == L('\0'))
+ /* The wildcard(s) is/are the last element of the pattern.
+ If the name is a file name and contains another slash
+ this means it cannot match, unless the FNM_LEADING_DIR
+ flag is set. */
+ {
+ int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
+
+ if (flags & FNM_FILE_NAME)
+ {
+ if (flags & FNM_LEADING_DIR)
+ result = 0;
+ else
+ {
+ if (MEMCHR (n, L('/'), string_end - n) == NULL)
+ result = 0;
+ }
+ }
+
+ return result;
+ }
+ else
+ {
+ const CHAR *endp;
+
+ endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'),
+ string_end - n);
+ if (endp == NULL)
+ endp = string_end;
+
+ if (c == L('[')
+ || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
+ && (c == L('@') || c == L('+') || c == L('!'))
+ && *p == L('(')))
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ int no_leading_period2 = no_leading_period;
+
+ for (--p; n < endp; ++n, no_leading_period2 = 0)
+ if (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0)
+ return 0;
+ }
+ else if (c == L('/') && (flags & FNM_FILE_NAME))
+ {
+ while (n < string_end && *n != L('/'))
+ ++n;
+ if (n < string_end && *n == L('/')
+ && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags)
+ == 0))
+ return 0;
+ }
+ else
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ int no_leading_period2 = no_leading_period;
+
+ if (c == L('\\') && !(flags & FNM_NOESCAPE))
+ c = *p;
+ c = FOLD (c);
+ for (--p; n < endp; ++n, no_leading_period2 = 0)
+ if (FOLD ((UCHAR) *n) == c
+ && (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0))
+ return 0;
+ }
+ }
+
+ /* If we come here no match is possible with the wildcard. */
+ return FNM_NOMATCH;
+
+ case L('['):
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+ CHAR cold;
+ UCHAR fn;
+
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+
+ if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ if (*n == L('/') && (flags & FNM_FILE_NAME))
+ /* `/' cannot be matched. */
+ return FNM_NOMATCH;
+
+ not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
+ if (not)
+ ++p;
+
+ fn = FOLD ((UCHAR) *n);
+
+ c = *p++;
+ for (;;)
+ {
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ c = FOLD ((UCHAR) *p);
+ ++p;
+
+ goto normal_bracket;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ /* Leave room for the null. */
+ CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
+ size_t c1 = 0;
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wctype_t wt;
+#endif
+ const CHAR *startp = p;
+
+ for (;;)
+ {
+ if (c1 == CHAR_CLASS_MAX_LENGTH)
+ /* The name is too long and therefore the pattern
+ is ill-formed. */
+ return FNM_NOMATCH;
+
+ c = *++p;
+ if (c == L(':') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c < L('a') || c >= L('z'))
+ {
+ /* This cannot possibly be a character class name.
+ Match it as a normal range. */
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[c1++] = c;
+ }
+ str[c1] = L('\0');
+
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wt = IS_CHAR_CLASS (str);
+ if (wt == 0)
+ /* Invalid character class name. */
+ return FNM_NOMATCH;
+
+# if defined _LIBC && ! WIDE_CHAR_VERSION
+ /* The following code is glibc specific but does
+ there a good job in speeding up the code since
+ we can avoid the btowc() call. */
+ if (_ISCTYPE ((UCHAR) *n, wt))
+ goto matched;
+# else
+ if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
+ goto matched;
+# endif
+#else
+ if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
+ || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
+ || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
+ || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
+ || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
+ || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
+ || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
+ || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
+ || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
+ || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
+ || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
+ || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
+ goto matched;
+#endif
+ c = *p++;
+ }
+#ifdef _LIBC
+ else if (c == L('[') && *p == L('='))
+ {
+ UCHAR str[1];
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+
+ c = *++p;
+ if (c == L('\0'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[0] = c;
+
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ p += 2;
+
+ if (nrules == 0)
+ {
+ if ((UCHAR) *n == str[0])
+ goto matched;
+ }
+ else
+ {
+ const int32_t *table;
+# if WIDE_CHAR_VERSION
+ const int32_t *weights;
+ const int32_t *extra;
+# else
+ const unsigned char *weights;
+ const unsigned char *extra;
+# endif
+ const int32_t *indirect;
+ int32_t idx;
+ const UCHAR *cp = (const UCHAR *) str;
+
+ /* This #include defines a local function! */
+# if WIDE_CHAR_VERSION
+# include <locale/weightwc.h>
+# else
+# include <locale/weight.h>
+# endif
+
+# if WIDE_CHAR_VERSION
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
+ weights = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
+ extra = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
+# else
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+# endif
+
+ idx = findidx (&cp);
+ if (idx != 0)
+ {
+ /* We found a table entry. Now see whether the
+ character we are currently at has the same
+ equivalance class value. */
+ int len = weights[idx];
+ int32_t idx2;
+ const UCHAR *np = (const UCHAR *) n;
+
+ idx2 = findidx (&np);
+ if (idx2 != 0 && len == weights[idx2])
+ {
+ int cnt = 0;
+
+ while (cnt < len
+ && (weights[idx + 1 + cnt]
+ == weights[idx2 + 1 + cnt]))
+ ++cnt;
+
+ if (cnt == len)
+ goto matched;
+ }
+ }
+ }
+
+ c = *p++;
+ }
+#endif
+ else if (c == L('\0'))
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+ else
+ {
+ int is_range = 0;
+
+#ifdef _LIBC
+ int is_seqval = 0;
+
+ if (c == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = *p == L('-') && p[1] != L('\0');
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the collation
+ data. Therefore we only accept the trivial
+ names consisting of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ if (!is_range && *n == startp[1])
+ goto matched;
+
+ cold = startp[1];
+ c = *p++;
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ unsigned int strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* We have to convert the name to a single-byte
+ string. This is possible since the names
+ consist of ASCII characters and the internal
+ representation is UCS4. */
+ for (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+#endif
+
+ table_size =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+
+ /* Locate the character in the hashing table. */
+ hash = elem_hash (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ && (c1
+ == extra[symb_table[2 * elem + 1]])
+ && memcmp (str,
+ &extra[symb_table[2 * elem
+ + 1]
+ + 1], c1) == 0)
+ {
+ /* Yep, this is the entry. */
+ idx = symb_table[2 * elem + 1];
+ idx += 1 + extra[idx];
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+
+ if (! is_range)
+ {
+# ifdef WIDE_CHAR_VERSION
+ for (c1 = 0;
+ (int32_t) c1 < wextra[idx];
+ ++c1)
+ if (n[c1] != wextra[1 + c1])
+ break;
+
+ if ((int32_t) c1 == wextra[idx])
+ goto matched;
+# else
+ for (c1 = 0; c1 < extra[idx]; ++c1)
+ if (n[c1] != extra[1 + c1])
+ break;
+
+ if (c1 == extra[idx])
+ goto matched;
+# endif
+ }
+
+ /* Get the collation sequence value. */
+ is_seqval = 1;
+# ifdef WIDE_CHAR_VERSION
+ cold = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cold = *((int32_t *) &extra[idx]);
+# endif
+
+ c = *p++;
+ }
+ else if (c1 == 1)
+ {
+ /* No valid character. Match it as a
+ single byte. */
+ if (!is_range && *n == str[0])
+ goto matched;
+
+ cold = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+ }
+ else
+# undef str
+#endif
+ {
+ c = FOLD (c);
+ normal_bracket:
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = (*p == L('-') && p[1] != L('\0')
+ && p[1] != L(']'));
+
+ if (!is_range && c == fn)
+ goto matched;
+
+ /* This is needed if we goto normal_bracket; from
+ outside of is_seqval's scope. */
+ is_seqval = 0;
+ cold = c;
+ c = *p++;
+ }
+
+ if (c == L('-') && *p != L(']'))
+ {
+#if _LIBC
+ /* We have to find the collation sequence
+ value for C. Collation sequence is nothing
+ we can regularly access. The sequence
+ value is defined by the order in which the
+ definitions of the collation values for the
+ various characters appear in the source
+ file. A strange concept, nowhere
+ documented. */
+ uint32_t fcollseq;
+ uint32_t lcollseq;
+ UCHAR cend = *p++;
+
+# ifdef WIDE_CHAR_VERSION
+ /* Search in the `names' array for the characters. */
+ fcollseq = __collseq_table_lookup (collseq, fn);
+ if (fcollseq == ~((uint32_t) 0))
+ /* XXX We don't know anything about the character
+ we are supposed to match. This means we are
+ failing. */
+ goto range_not_matched;
+
+ if (is_seqval)
+ lcollseq = cold;
+ else
+ lcollseq = __collseq_table_lookup (collseq, cold);
+# else
+ fcollseq = collseq[fn];
+ lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
+# endif
+
+ is_seqval = 0;
+ if (cend == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the
+ collation data. Therefore we only
+ accept the trivial names consisting
+ of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ cend = startp[1];
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ unsigned int strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* We have to convert the name to a single-byte
+ string. This is possible since the names
+ consist of ASCII characters and the internal
+ representation is UCS4. */
+ for (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+# endif
+
+ table_size =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+
+ /* Locate the character in the hashing
+ table. */
+ hash = elem_hash (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ && (c1
+ == extra[symb_table[2 * elem + 1]])
+ && memcmp (str,
+ &extra[symb_table[2 * elem + 1]
+ + 1], c1) == 0)
+ {
+ /* Yep, this is the entry. */
+ idx = symb_table[2 * elem + 1];
+ idx += 1 + extra[idx];
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~4;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+ /* Get the collation sequence value. */
+ is_seqval = 1;
+# ifdef WIDE_CHAR_VERSION
+ cend = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cend = *((int32_t *) &extra[idx]);
+# endif
+ }
+ else if (symb_table[2 * elem] != 0 && c1 == 1)
+ {
+ cend = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+# undef str
+ }
+ else
+ {
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+ }
+
+ /* XXX It is not entirely clear to me how to handle
+ characters which are not mentioned in the
+ collation specification. */
+ if (
+# ifdef WIDE_CHAR_VERSION
+ lcollseq == 0xffffffff ||
+# endif
+ lcollseq <= fcollseq)
+ {
+ /* We have to look at the upper bound. */
+ uint32_t hcollseq;
+
+ if (is_seqval)
+ hcollseq = cend;
+ else
+ {
+# ifdef WIDE_CHAR_VERSION
+ hcollseq =
+ __collseq_table_lookup (collseq, cend);
+ if (hcollseq == ~((uint32_t) 0))
+ {
+ /* Hum, no information about the upper
+ bound. The matching succeeds if the
+ lower bound is matched exactly. */
+ if (lcollseq != fcollseq)
+ goto range_not_matched;
+
+ goto matched;
+ }
+# else
+ hcollseq = collseq[cend];
+# endif
+ }
+
+ if (lcollseq <= hcollseq && fcollseq <= hcollseq)
+ goto matched;
+ }
+# ifdef WIDE_CHAR_VERSION
+ range_not_matched:
+# endif
+#else
+ /* We use a boring value comparison of the character
+ values. This is better than comparing using
+ `strcoll' since the latter would have surprising
+ and sometimes fatal consequences. */
+ UCHAR cend = *p++;
+
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+
+ /* It is a range. */
+ if (cold <= fn && fn <= cend)
+ goto matched;
+#endif
+
+ c = *p++;
+ }
+ }
+
+ if (c == L(']'))
+ break;
+ }
+
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:
+ /* Skip the rest of the [...] that already matched. */
+ do
+ {
+ ignore_next:
+ c = *p++;
+
+ if (c == L('\0'))
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ int c1 = 0;
+ const CHAR *startp = p;
+
+ while (1)
+ {
+ c = *++p;
+ if (++c1 == CHAR_CLASS_MAX_LENGTH)
+ return FNM_NOMATCH;
+
+ if (*p == L(':') && p[1] == L(']'))
+ break;
+
+ if (c < L('a') || c >= L('z'))
+ {
+ p = startp;
+ goto ignore_next;
+ }
+ }
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('='))
+ {
+ c = *++p;
+ if (c == L('\0'))
+ return FNM_NOMATCH;
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ return FNM_NOMATCH;
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('.'))
+ {
+ ++p;
+ while (1)
+ {
+ c = *++p;
+ if (c == '\0')
+ return FNM_NOMATCH;
+
+ if (*p == L('.') && p[1] == L(']'))
+ break;
+ }
+ p += 2;
+ c = *p++;
+ }
+ }
+ while (c != L(']'));
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ case L('+'):
+ case L('@'):
+ case L('!'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period, flags);
+ if (res != -1)
+ return res;
+ }
+ goto normal_match;
+
+ case L('/'):
+ if (NO_LEADING_PERIOD (flags))
+ {
+ if (n == string_end || c != (UCHAR) *n)
+ return FNM_NOMATCH;
+
+ new_no_leading_period = 1;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ normal_match:
+ if (n == string_end || c != FOLD ((UCHAR) *n))
+ return FNM_NOMATCH;
+ }
+
+ no_leading_period = new_no_leading_period;
+ ++n;
+ }
+
+ if (n == string_end)
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/'))
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+
+static const CHAR *
+internal_function
+END (const CHAR *pattern)
+{
+ const CHAR *p = pattern;
+
+ while (1)
+ if (*++p == L('\0'))
+ /* This is an invalid pattern. */
+ return pattern;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return pattern;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ p = END (p + 1);
+ else if (*p == L(')'))
+ break;
+
+ return p + 1;
+}
+
+
+static int
+internal_function
+EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
+ int no_leading_period, int flags)
+{
+ const CHAR *startp;
+ int level;
+ struct patternlist
+ {
+ struct patternlist *next;
+ CHAR str[0];
+ } *list = NULL;
+ struct patternlist **lastp = &list;
+ size_t pattern_len = STRLEN (pattern);
+ const CHAR *p;
+ const CHAR *rs;
+
+ /* Parse the pattern. Store the individual parts in the list. */
+ level = 0;
+ for (startp = p = pattern + 1; level >= 0; ++p)
+ if (*p == L('\0'))
+ /* This is an invalid pattern. */
+ return -1;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return -1;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ /* Remember the nesting level. */
+ ++level;
+ else if (*p == L(')'))
+ {
+ if (level-- == 0)
+ {
+ /* This means we found the end of the pattern. */
+#define NEW_PATTERN \
+ struct patternlist *newp; \
+ \
+ if (opt == L('?') || opt == L('@')) \
+ newp = alloca (sizeof (struct patternlist) \
+ + (pattern_len * sizeof (CHAR))); \
+ else \
+ newp = alloca (sizeof (struct patternlist) \
+ + ((p - startp + 1) * sizeof (CHAR))); \
+ *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \
+ newp->next = NULL; \
+ *lastp = newp; \
+ lastp = &newp->next
+ NEW_PATTERN;
+ }
+ }
+ else if (*p == L('|'))
+ {
+ if (level == 0)
+ {
+ NEW_PATTERN;
+ startp = p + 1;
+ }
+ }
+ assert (list != NULL);
+ assert (p[-1] == L(')'));
+#undef NEW_PATTERN
+
+ switch (opt)
+ {
+ case L('*'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('+'):
+ do
+ {
+ for (rs = string; rs <= string_end; ++rs)
+ /* First match the prefix with the current pattern with the
+ current pattern. */
+ if (FCT (list->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
+ /* This was successful. Now match the rest with the rest
+ of the pattern. */
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0
+ /* This didn't work. Try the whole pattern. */
+ || (rs != string
+ && FCT (pattern - 1, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
+ ? 1 : 0),
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0)))
+ /* It worked. Signal success. */
+ return 0;
+ }
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('?'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('@'):
+ do
+ /* I cannot believe it but `strcat' is actually acceptable
+ here. Match the entire string with the prefix from the
+ pattern list and the rest of the pattern following the
+ pattern list. */
+ if (FCT (STRCAT (list->str, p), string, string_end,
+ no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ /* It worked. Signal success. */
+ return 0;
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('!'):
+ for (rs = string; rs <= string_end; ++rs)
+ {
+ struct patternlist *runp;
+
+ for (runp = list; runp != NULL; runp = runp->next)
+ if (FCT (runp->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ break;
+
+ /* If none of the patterns matched see whether the rest does. */
+ if (runp == NULL
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
+ == 0))
+ /* This is successful. */
+ return 0;
+ }
+
+ /* None of the patterns together with the rest of the pattern
+ lead to a match. */
+ return FNM_NOMATCH;
+
+ default:
+ assert (! "Invalid extended matching operator");
+ break;
+ }
+
+ return -1;
+}
+
+
+#undef FOLD
+#undef CHAR
+#undef UCHAR
+#undef INT
+#undef FCT
+#undef EXT
+#undef END
+#undef MEMPCPY
+#undef MEMCHR
+#undef STRCOLL
+#undef STRLEN
+#undef STRCAT
+#undef L
+#undef BTOWC
diff --git a/libc/posix/fork.c b/libc/posix/fork.c
new file mode 100644
index 000000000..c19fa656b
--- /dev/null
+++ b/libc/posix/fork.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Clone the calling process, creating an exact copy.
+ Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+int
+__fork ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__fork)
+stub_warning (fork)
+
+weak_alias (__fork, fork)
+#include <stub-tag.h>
diff --git a/libc/posix/fpathconf.c b/libc/posix/fpathconf.c
new file mode 100644
index 000000000..840460b04
--- /dev/null
+++ b/libc/posix/fpathconf.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Get file-specific information about descriptor FD. */
+long int
+__fpathconf (fd, name)
+ int fd;
+ int name;
+{
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+
+ switch (name)
+ {
+ default:
+ __set_errno (EINVAL);
+ return -1;
+
+ case _PC_LINK_MAX:
+ case _PC_MAX_CANON:
+ case _PC_MAX_INPUT:
+ case _PC_NAME_MAX:
+ case _PC_PATH_MAX:
+ case _PC_PIPE_BUF:
+ case _PC_SOCK_MAXBUF:
+ case _PC_CHOWN_RESTRICTED:
+ case _PC_NO_TRUNC:
+ case _PC_VDISABLE:
+ break;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+weak_alias (__fpathconf, fpathconf)
+
+stub_warning (fpathconf)
+#include <stub-tag.h>
diff --git a/libc/posix/gai.conf b/libc/posix/gai.conf
new file mode 100644
index 000000000..0e334ac2c
--- /dev/null
+++ b/libc/posix/gai.conf
@@ -0,0 +1,52 @@
+# Configuration for getaddrinfo(3).
+#
+# So far only configuration for the destination address sorting is needed.
+# RFC 3484 governs the sorting. But the RFC also says that system
+# administrators should be able to overwrite the defaults. This can be
+# achieved here.
+#
+# All lines have an initial identifier specifying the option followed by
+# up to two values. Information specified in this file replaces the
+# default information. Complete absence of data of one kind causes the
+# appropriate default information to be used. The supported commands include:
+#
+# reload <yes|no>
+# If set to yes, each getaddrinfo(3) call will check whether this file
+# changed and if necessary reload. This option should not really be
+# used. There are possible runtime problems. The default is no.
+#
+# label <mask> <value>
+# Add another rule to the RFC 3484 label table. See section 2.1 in
+# RFC 3484. The default is:
+#
+#label ::1/128 0
+#label ::/0 1
+#label 2002::/16 2
+#label ::/96 3
+#label ::ffff:0:0/96 4
+#label fec0::/10 5
+#label fc00::/7 6
+#
+# This default differs from the tables given in RFC 3484 by handling
+# (now obsolete) site-local IPv6 addresses and Unique Local Addresses.
+# The reason for this difference is that these addresses are never
+# NATed while IPv4 site-local addresses most probably are. Given
+# the precedence of IPv6 over IPv4 (see below) on machines having only
+# site-local IPv4 and IPv6 addresses a lookup for a global address would
+# see the IPv6 be preferred. The result is a long delay because the
+# site-local IPv6 addresses cannot be used while the IPv4 address is
+# (at least for the foreseeable future) NATed.
+#
+# precedence <mask> <value>
+# Add another rule the to RFC 3484 precedence table. See section 2.1
+# and 10.3 in RFC 3484. The default is:
+#
+#precedence ::1/128 50
+#precedence ::/0 40
+#precedence 2002::/16 30
+#precedence ::/96 20
+#precedence ::ffff:0:0/96 10
+#
+# For sites which prefer IPv4 connections change the last line to
+#
+#precedence ::ffff:0:0/96 100
diff --git a/libc/posix/gai_strerror.c b/libc/posix/gai_strerror.c
new file mode 100644
index 000000000..932c5910d
--- /dev/null
+++ b/libc/posix/gai_strerror.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 1996,97,2001,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <netdb.h>
+
+const char *
+gai_strerror (int code)
+{
+ static char buffer[128];
+ snprintf (buffer, sizeof buffer, "Unknown error (%d)", code);
+ return buffer;
+}
+libc_hidden_def (gai_strerror)
diff --git a/libc/posix/get_child_max.c b/libc/posix/get_child_max.c
new file mode 100644
index 000000000..dd68d91d3
--- /dev/null
+++ b/libc/posix/get_child_max.c
@@ -0,0 +1,29 @@
+/* Get POSIX {CHILD_MAX} run-time limit value. Stub version (no limit).
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <limits.h>
+#include <sys/sysinfo.h>
+
+#ifndef CHILD_MAX
+long int
+__get_child_max (void)
+{
+ return -1;
+}
+#endif
diff --git a/libc/posix/getaddrinfo.c b/libc/posix/getaddrinfo.c
new file mode 100644
index 000000000..548c0b863
--- /dev/null
+++ b/libc/posix/getaddrinfo.c
@@ -0,0 +1,41 @@
+/* Stub version of getaddrinfo function.
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <netdb.h>
+
+int
+getaddrinfo (const char *name, const char *service, const struct addrinfo *req,
+ struct addrinfo **pai)
+{
+ __set_errno (ENOSYS);
+ return EAI_SYSTEM;
+}
+stub_warning (getaddrinfo)
+libc_hidden_def (getaddrinfo)
+
+void
+freeaddrinfo (struct addrinfo *ai)
+{
+ /* Nothing. */
+}
+stub_warning (freeaddrinfo)
+libc_hidden_def (freeaddrinfo)
+
+#include <stub-tag.h>
diff --git a/libc/posix/getconf.c b/libc/posix/getconf.c
new file mode 100644
index 000000000..3c5ffe454
--- /dev/null
+++ b/libc/posix/getconf.c
@@ -0,0 +1,1171 @@
+/* Copyright (C) 1991, 92, 1995-2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <error.h>
+#include <libintl.h>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../version.h"
+#define PACKAGE _libc_intl_domainname
+
+struct conf
+ {
+ const char *name;
+ const int call_name;
+ const enum { SYSCONF, CONFSTR, PATHCONF } call;
+ };
+
+static const struct conf vars[] =
+ {
+#ifdef _PC_LINK_MAX
+ { "LINK_MAX", _PC_LINK_MAX, PATHCONF },
+#endif
+#ifdef _PC_LINK_MAX
+ { "_POSIX_LINK_MAX", _PC_LINK_MAX, PATHCONF },
+#endif
+#ifdef _PC_MAX_CANON
+ { "MAX_CANON", _PC_MAX_CANON, PATHCONF },
+#endif
+#ifdef _PC_MAX_CANON
+ { "_POSIX_MAX_CANON", _PC_MAX_CANON, PATHCONF },
+#endif
+#ifdef _PC_MAX_INPUT
+ { "MAX_INPUT", _PC_MAX_INPUT, PATHCONF },
+#endif
+#ifdef _PC_MAX_INPUT
+ { "_POSIX_MAX_INPUT", _PC_MAX_INPUT, PATHCONF },
+#endif
+#ifdef _PC_NAME_MAX
+ { "NAME_MAX", _PC_NAME_MAX, PATHCONF },
+#endif
+#ifdef _PC_NAME_MAX
+ { "_POSIX_NAME_MAX", _PC_NAME_MAX, PATHCONF },
+#endif
+#ifdef _PC_PATH_MAX
+ { "PATH_MAX", _PC_PATH_MAX, PATHCONF },
+#endif
+#ifdef _PC_PATH_MAX
+ { "_POSIX_PATH_MAX", _PC_PATH_MAX, PATHCONF },
+#endif
+#ifdef _PC_PIPE_BUF
+ { "PIPE_BUF", _PC_PIPE_BUF, PATHCONF },
+#endif
+#ifdef _PC_PIPE_BUF
+ { "_POSIX_PIPE_BUF", _PC_PIPE_BUF, PATHCONF },
+#endif
+#ifdef _PC_SOCK_MAXBUF
+ { "SOCK_MAXBUF", _PC_SOCK_MAXBUF, PATHCONF },
+#endif
+#ifdef _PC_ASYNC_IO
+ { "_POSIX_ASYNC_IO", _PC_ASYNC_IO, PATHCONF },
+#endif
+#ifdef _PC_CHOWN_RESTRICTED
+ { "_POSIX_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED, PATHCONF },
+#endif
+#ifdef _PC_NO_TRUNC
+ { "_POSIX_NO_TRUNC", _PC_NO_TRUNC, PATHCONF },
+#endif
+#ifdef _PC_PRIO_IO
+ { "_POSIX_PRIO_IO", _PC_PRIO_IO, PATHCONF },
+#endif
+#ifdef _PC_SYNC_IO
+ { "_POSIX_SYNC_IO", _PC_SYNC_IO, PATHCONF },
+#endif
+#ifdef _PC_VDISABLE
+ { "_POSIX_VDISABLE", _PC_VDISABLE, PATHCONF },
+#endif
+
+#ifdef _SC_ARG_MAX
+ { "ARG_MAX", _SC_ARG_MAX, SYSCONF },
+#endif
+#ifdef _SC_ATEXIT_MAX
+ { "ATEXIT_MAX", _SC_ATEXIT_MAX, SYSCONF },
+#endif
+#ifdef _SC_CHAR_BIT
+ { "CHAR_BIT", _SC_CHAR_BIT, SYSCONF },
+#endif
+#ifdef _SC_CHAR_MAX
+ { "CHAR_MAX", _SC_CHAR_MAX, SYSCONF },
+#endif
+#ifdef _SC_CHAR_MIN
+ { "CHAR_MIN", _SC_CHAR_MIN, SYSCONF },
+#endif
+#ifdef _SC_CHILD_MAX
+ { "CHILD_MAX", _SC_CHILD_MAX, SYSCONF },
+#endif
+#ifdef _SC_CLK_TCK
+ { "CLK_TCK", _SC_CLK_TCK, SYSCONF },
+#endif
+#ifdef _SC_INT_MAX
+ { "INT_MAX", _SC_INT_MAX, SYSCONF },
+#endif
+#ifdef _SC_INT_MIN
+ { "INT_MIN", _SC_INT_MIN, SYSCONF },
+#endif
+#ifdef _SC_UIO_MAXIOV
+ { "IOV_MAX", _SC_UIO_MAXIOV, SYSCONF },
+#endif
+#ifdef _SC_LOGIN_NAME_MAX
+ { "LOGNAME_MAX", _SC_LOGIN_NAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_LONG_BIT
+ { "LONG_BIT", _SC_LONG_BIT, SYSCONF },
+#endif
+#ifdef _SC_MB_LEN_MAX
+ { "MB_LEN_MAX", _SC_MB_LEN_MAX, SYSCONF },
+#endif
+#ifdef _SC_NGROUPS_MAX
+ { "NGROUPS_MAX", _SC_NGROUPS_MAX, SYSCONF },
+#endif
+#ifdef _SC_NL_ARGMAX
+ { "NL_ARGMAX", _SC_NL_ARGMAX, SYSCONF },
+#endif
+#ifdef _SC_NL_LANGMAX
+ { "NL_LANGMAX", _SC_NL_LANGMAX, SYSCONF },
+#endif
+#ifdef _SC_NL_MSGMAX
+ { "NL_MSGMAX", _SC_NL_MSGMAX, SYSCONF },
+#endif
+#ifdef _SC_NL_NMAX
+ { "NL_NMAX", _SC_NL_NMAX, SYSCONF },
+#endif
+#ifdef _SC_NL_SETMAX
+ { "NL_SETMAX", _SC_NL_SETMAX, SYSCONF },
+#endif
+#ifdef _SC_NL_TEXTMAX
+ { "NL_TEXTMAX", _SC_NL_TEXTMAX, SYSCONF },
+#endif
+#ifdef _SC_GETGR_R_SIZE_MAX
+ { "NSS_BUFLEN_GROUP", _SC_GETGR_R_SIZE_MAX, SYSCONF },
+#endif
+#ifdef _SC_GETPW_R_SIZE_MAX
+ { "NSS_BUFLEN_PASSWD", _SC_GETPW_R_SIZE_MAX, SYSCONF },
+#endif
+#ifdef _SC_NZERO
+ { "NZERO", _SC_NZERO, SYSCONF },
+#endif
+#ifdef _SC_OPEN_MAX
+ { "OPEN_MAX", _SC_OPEN_MAX, SYSCONF },
+#endif
+#ifdef _SC_PAGESIZE
+ { "PAGESIZE", _SC_PAGESIZE, SYSCONF },
+#endif
+#ifdef _SC_PAGESIZE
+ { "PAGE_SIZE", _SC_PAGESIZE, SYSCONF },
+#endif
+#ifdef _SC_PASS_MAX
+ { "PASS_MAX", _SC_PASS_MAX, SYSCONF },
+#endif
+#ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS
+ { "PTHREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS, SYSCONF },
+#endif
+#ifdef _SC_THREAD_KEYS_MAX
+ { "PTHREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX, SYSCONF },
+#endif
+#ifdef _SC_THREAD_STACK_MIN
+ { "PTHREAD_STACK_MIN", _SC_THREAD_STACK_MIN, SYSCONF },
+#endif
+#ifdef _SC_THREAD_THREADS_MAX
+ { "PTHREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX, SYSCONF },
+#endif
+#ifdef _SC_SCHAR_MAX
+ { "SCHAR_MAX", _SC_SCHAR_MAX, SYSCONF },
+#endif
+#ifdef _SC_SCHAR_MIN
+ { "SCHAR_MIN", _SC_SCHAR_MIN, SYSCONF },
+#endif
+#ifdef _SC_SHRT_MAX
+ { "SHRT_MAX", _SC_SHRT_MAX, SYSCONF },
+#endif
+#ifdef _SC_SHRT_MIN
+ { "SHRT_MIN", _SC_SHRT_MIN, SYSCONF },
+#endif
+#ifdef _SC_SSIZE_MAX
+ { "SSIZE_MAX", _SC_SSIZE_MAX, SYSCONF },
+#endif
+#ifdef _SC_TTY_NAME_MAX
+ { "TTY_NAME_MAX", _SC_TTY_NAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_TZNAME_MAX
+ { "TZNAME_MAX", _SC_TZNAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_UCHAR_MAX
+ { "UCHAR_MAX", _SC_UCHAR_MAX, SYSCONF },
+#endif
+#ifdef _SC_UINT_MAX
+ { "UINT_MAX", _SC_UINT_MAX, SYSCONF },
+#endif
+#ifdef _SC_UIO_MAXIOV
+ { "UIO_MAXIOV", _SC_UIO_MAXIOV, SYSCONF },
+#endif
+#ifdef _SC_ULONG_MAX
+ { "ULONG_MAX", _SC_ULONG_MAX, SYSCONF },
+#endif
+#ifdef _SC_USHRT_MAX
+ { "USHRT_MAX", _SC_USHRT_MAX, SYSCONF },
+#endif
+#ifdef _SC_WORD_BIT
+ { "WORD_BIT", _SC_WORD_BIT, SYSCONF },
+#endif
+#ifdef _SC_AVPHYS_PAGES
+ { "_AVPHYS_PAGES", _SC_AVPHYS_PAGES, SYSCONF },
+#endif
+#ifdef _SC_NPROCESSORS_CONF
+ { "_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF, SYSCONF },
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+ { "_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN, SYSCONF },
+#endif
+#ifdef _SC_PHYS_PAGES
+ { "_PHYS_PAGES", _SC_PHYS_PAGES, SYSCONF },
+#endif
+#ifdef _SC_ARG_MAX
+ { "_POSIX_ARG_MAX", _SC_ARG_MAX, SYSCONF },
+#endif
+#ifdef _SC_ASYNCHRONOUS_IO
+ { "_POSIX_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO, SYSCONF },
+#endif
+#ifdef _SC_CHILD_MAX
+ { "_POSIX_CHILD_MAX", _SC_CHILD_MAX, SYSCONF },
+#endif
+#ifdef _SC_FSYNC
+ { "_POSIX_FSYNC", _SC_FSYNC, SYSCONF },
+#endif
+#ifdef _SC_JOB_CONTROL
+ { "_POSIX_JOB_CONTROL", _SC_JOB_CONTROL, SYSCONF },
+#endif
+#ifdef _SC_MAPPED_FILES
+ { "_POSIX_MAPPED_FILES", _SC_MAPPED_FILES, SYSCONF },
+#endif
+#ifdef _SC_MEMLOCK
+ { "_POSIX_MEMLOCK", _SC_MEMLOCK, SYSCONF },
+#endif
+#ifdef _SC_MEMLOCK_RANGE
+ { "_POSIX_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE, SYSCONF },
+#endif
+#ifdef _SC_MEMORY_PROTECTION
+ { "_POSIX_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION, SYSCONF },
+#endif
+#ifdef _SC_MESSAGE_PASSING
+ { "_POSIX_MESSAGE_PASSING", _SC_MESSAGE_PASSING, SYSCONF },
+#endif
+#ifdef _SC_NGROUPS_MAX
+ { "_POSIX_NGROUPS_MAX", _SC_NGROUPS_MAX, SYSCONF },
+#endif
+#ifdef _SC_OPEN_MAX
+ { "_POSIX_OPEN_MAX", _SC_OPEN_MAX, SYSCONF },
+#endif
+#ifdef _SC_PII
+ { "_POSIX_PII", _SC_PII, SYSCONF },
+#endif
+#ifdef _SC_PII_INTERNET
+ { "_POSIX_PII_INTERNET", _SC_PII_INTERNET, SYSCONF },
+#endif
+#ifdef _SC_PII_INTERNET_DGRAM
+ { "_POSIX_PII_INTERNET_DGRAM", _SC_PII_INTERNET_DGRAM, SYSCONF },
+#endif
+#ifdef _SC_PII_INTERNET_STREAM
+ { "_POSIX_PII_INTERNET_STREAM", _SC_PII_INTERNET_STREAM, SYSCONF },
+#endif
+#ifdef _SC_PII_OSI
+ { "_POSIX_PII_OSI", _SC_PII_OSI, SYSCONF },
+#endif
+#ifdef _SC_PII_OSI_CLTS
+ { "_POSIX_PII_OSI_CLTS", _SC_PII_OSI_CLTS, SYSCONF },
+#endif
+#ifdef _SC_PII_OSI_COTS
+ { "_POSIX_PII_OSI_COTS", _SC_PII_OSI_COTS, SYSCONF },
+#endif
+#ifdef _SC_PII_OSI_M
+ { "_POSIX_PII_OSI_M", _SC_PII_OSI_M, SYSCONF },
+#endif
+#ifdef _SC_PII_SOCKET
+ { "_POSIX_PII_SOCKET", _SC_PII_SOCKET, SYSCONF },
+#endif
+#ifdef _SC_PII_XTI
+ { "_POSIX_PII_XTI", _SC_PII_XTI, SYSCONF },
+#endif
+#ifdef _SC_POLL
+ { "_POSIX_POLL", _SC_POLL, SYSCONF },
+#endif
+#ifdef _SC_PRIORITIZED_IO
+ { "_POSIX_PRIORITIZED_IO", _SC_PRIORITIZED_IO, SYSCONF },
+#endif
+#ifdef _SC_PRIORITY_SCHEDULING
+ { "_POSIX_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING, SYSCONF },
+#endif
+#ifdef _SC_REALTIME_SIGNALS
+ { "_POSIX_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS, SYSCONF },
+#endif
+#ifdef _SC_SAVED_IDS
+ { "_POSIX_SAVED_IDS", _SC_SAVED_IDS, SYSCONF },
+#endif
+#ifdef _SC_SELECT
+ { "_POSIX_SELECT", _SC_SELECT, SYSCONF },
+#endif
+#ifdef _SC_SEMAPHORES
+ { "_POSIX_SEMAPHORES", _SC_SEMAPHORES, SYSCONF },
+#endif
+#ifdef _SC_SHARED_MEMORY_OBJECTS
+ { "_POSIX_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS, SYSCONF },
+#endif
+#ifdef _SC_SSIZE_MAX
+ { "_POSIX_SSIZE_MAX", _SC_SSIZE_MAX, SYSCONF },
+#endif
+#ifdef _SC_STREAM_MAX
+ { "_POSIX_STREAM_MAX", _SC_STREAM_MAX, SYSCONF },
+#endif
+#ifdef _SC_SYNCHRONIZED_IO
+ { "_POSIX_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO, SYSCONF },
+#endif
+#ifdef _SC_THREADS
+ { "_POSIX_THREADS", _SC_THREADS, SYSCONF },
+#endif
+#ifdef _SC_THREAD_ATTR_STACKADDR
+ { "_POSIX_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR, SYSCONF },
+#endif
+#ifdef _SC_THREAD_ATTR_STACKSIZE
+ { "_POSIX_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE, SYSCONF },
+#endif
+#ifdef _SC_THREAD_PRIORITY_SCHEDULING
+ { "_POSIX_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING, SYSCONF },
+#endif
+#ifdef _SC_THREAD_PRIO_INHERIT
+ { "_POSIX_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT, SYSCONF },
+#endif
+#ifdef _SC_THREAD_PRIO_PROTECT
+ { "_POSIX_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT, SYSCONF },
+#endif
+#ifdef _SC_THREAD_PROCESS_SHARED
+ { "_POSIX_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED, SYSCONF },
+#endif
+#ifdef _SC_THREAD_SAFE_FUNCTIONS
+ { "_POSIX_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS, SYSCONF },
+#endif
+#ifdef _SC_TIMERS
+ { "_POSIX_TIMERS", _SC_TIMERS, SYSCONF },
+#endif
+#ifdef _SC_TIMER_MAX
+ { "TIMER_MAX", _SC_TIMER_MAX, SYSCONF },
+#endif
+#ifdef _SC_TZNAME_MAX
+ { "_POSIX_TZNAME_MAX", _SC_TZNAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_VERSION
+ { "_POSIX_VERSION", _SC_VERSION, SYSCONF },
+#endif
+#ifdef _SC_T_IOV_MAX
+ { "_T_IOV_MAX", _SC_T_IOV_MAX, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_CRYPT
+ { "_XOPEN_CRYPT", _SC_XOPEN_CRYPT, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_ENH_I18N
+ { "_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_LEGACY
+ { "_XOPEN_LEGACY", _SC_XOPEN_LEGACY, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_REALTIME
+ { "_XOPEN_REALTIME", _SC_XOPEN_REALTIME, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_REALTIME_THREADS
+ { "_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_SHM
+ { "_XOPEN_SHM", _SC_XOPEN_SHM, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_UNIX
+ { "_XOPEN_UNIX", _SC_XOPEN_UNIX, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_VERSION
+ { "_XOPEN_VERSION", _SC_XOPEN_VERSION, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_XCU_VERSION
+ { "_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_XPG2
+ { "_XOPEN_XPG2", _SC_XOPEN_XPG2, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_XPG3
+ { "_XOPEN_XPG3", _SC_XOPEN_XPG3, SYSCONF },
+#endif
+#ifdef _SC_XOPEN_XPG4
+ { "_XOPEN_XPG4", _SC_XOPEN_XPG4, SYSCONF },
+#endif
+ /* POSIX.2 */
+#ifdef _SC_BC_BASE_MAX
+ { "BC_BASE_MAX", _SC_BC_BASE_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_DIM_MAX
+ { "BC_DIM_MAX", _SC_BC_DIM_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_SCALE_MAX
+ { "BC_SCALE_MAX", _SC_BC_SCALE_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_STRING_MAX
+ { "BC_STRING_MAX", _SC_BC_STRING_MAX, SYSCONF },
+#endif
+ { "CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX, SYSCONF },
+#ifdef _SC_COLL_WEIGHTS_MAX
+ { "COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX, SYSCONF },
+#endif
+#ifdef _SC_EQUIV_CLASS_MAX
+ { "EQUIV_CLASS_MAX", _SC_EQUIV_CLASS_MAX, SYSCONF },
+#endif
+#ifdef _SC_EXPR_NEST_MAX
+ { "EXPR_NEST_MAX", _SC_EXPR_NEST_MAX, SYSCONF },
+#endif
+#ifdef _SC_LINE_MAX
+ { "LINE_MAX", _SC_LINE_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_BASE_MAX
+ { "POSIX2_BC_BASE_MAX", _SC_BC_BASE_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_DIM_MAX
+ { "POSIX2_BC_DIM_MAX", _SC_BC_DIM_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_SCALE_MAX
+ { "POSIX2_BC_SCALE_MAX", _SC_BC_SCALE_MAX, SYSCONF },
+#endif
+#ifdef _SC_BC_STRING_MAX
+ { "POSIX2_BC_STRING_MAX", _SC_BC_STRING_MAX, SYSCONF },
+#endif
+#ifdef _SC_2_CHAR_TERM
+ { "POSIX2_CHAR_TERM", _SC_2_CHAR_TERM, SYSCONF },
+#endif
+#ifdef _SC_COLL_WEIGHTS_MAX
+ { "POSIX2_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX, SYSCONF },
+#endif
+#ifdef _SC_2_C_BIND
+ { "POSIX2_C_BIND", _SC_2_C_BIND, SYSCONF },
+#endif
+#ifdef _SC_2_C_DEV
+ { "POSIX2_C_DEV", _SC_2_C_DEV, SYSCONF },
+#endif
+#ifdef _SC_2_C_VERSION
+ { "POSIX2_C_VERSION", _SC_2_C_VERSION, SYSCONF },
+#endif
+#ifdef _SC_EXPR_NEST_MAX
+ { "POSIX2_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX, SYSCONF },
+#endif
+#ifdef _SC_2_FORT_DEV
+ { "POSIX2_FORT_DEV", _SC_2_FORT_DEV, SYSCONF },
+#endif
+#ifdef _SC_2_FORT_RUN
+ { "POSIX2_FORT_RUN", _SC_2_FORT_RUN, SYSCONF },
+#endif
+#ifdef _SC_LINE_MAX
+ { "_POSIX2_LINE_MAX", _SC_LINE_MAX, SYSCONF },
+#endif
+#ifdef _SC_2_LOCALEDEF
+ { "POSIX2_LOCALEDEF", _SC_2_LOCALEDEF, SYSCONF },
+#endif
+#ifdef _SC_RE_DUP_MAX
+ { "POSIX2_RE_DUP_MAX", _SC_RE_DUP_MAX, SYSCONF },
+#endif
+#ifdef _SC_2_SW_DEV
+ { "POSIX2_SW_DEV", _SC_2_SW_DEV, SYSCONF },
+#endif
+#ifdef _SC_2_UPE
+ { "POSIX2_UPE", _SC_2_UPE, SYSCONF },
+#endif
+#ifdef _SC_2_VERSION
+ { "POSIX2_VERSION", _SC_2_VERSION, SYSCONF },
+#endif
+#ifdef _SC_RE_DUP_MAX
+ { "RE_DUP_MAX", _SC_RE_DUP_MAX, SYSCONF },
+#endif
+
+#ifdef _CS_PATH
+ { "PATH", _CS_PATH, CONFSTR },
+ { "CS_PATH", _CS_PATH, CONFSTR },
+#endif
+
+ /* LFS */
+#ifdef _CS_LFS_CFLAGS
+ { "LFS_CFLAGS", _CS_LFS_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_LFS_LDFLAGS
+ { "LFS_LDFLAGS", _CS_LFS_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_LFS_LIBS
+ { "LFS_LIBS", _CS_LFS_LIBS, CONFSTR },
+#endif
+#ifdef _CS_LFS_LINTFLAGS
+ { "LFS_LINTFLAGS", _CS_LFS_LINTFLAGS, CONFSTR },
+#endif
+#ifdef _CS_LFS64_CFLAGS
+ { "LFS64_CFLAGS", _CS_LFS64_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_LFS64_LDFLAGS
+ { "LFS64_LDFLAGS", _CS_LFS64_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_LFS64_LIBS
+ { "LFS64_LIBS", _CS_LFS64_LIBS, CONFSTR },
+#endif
+#ifdef _CS_LFS64_LINTFLAGS
+ { "LFS64_LINTFLAGS", _CS_LFS64_LINTFLAGS, CONFSTR },
+#endif
+
+ /* Programming environments. */
+#ifdef _SC_XBS5_ILP32_OFF32
+ { "_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32, SYSCONF },
+#endif
+#ifdef _CS_XBS5_ILP32_OFF32_CFLAGS
+ { "XBS5_ILP32_OFF32_CFLAGS", _CS_XBS5_ILP32_OFF32_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFF32_LDFLAGS
+ { "XBS5_ILP32_OFF32_LDFLAGS", _CS_XBS5_ILP32_OFF32_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFF32_LIBS
+ { "XBS5_ILP32_OFF32_LIBS", _CS_XBS5_ILP32_OFF32_LIBS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFF32_LINTFLAGS
+ { "XBS5_ILP32_OFF32_LINTFLAGS", _CS_XBS5_ILP32_OFF32_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_XBS5_ILP32_OFFBIG
+ { "_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG, SYSCONF },
+#endif
+#ifdef _CS_XBS5_ILP32_OFFBIG_CFLAGS
+ { "XBS5_ILP32_OFFBIG_CFLAGS", _CS_XBS5_ILP32_OFFBIG_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFFBIG_LDFLAGS
+ { "XBS5_ILP32_OFFBIG_LDFLAGS", _CS_XBS5_ILP32_OFFBIG_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFFBIG_LIBS
+ { "XBS5_ILP32_OFFBIG_LIBS", _CS_XBS5_ILP32_OFFBIG_LIBS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_ILP32_OFFBIG_LINTFLAGS
+ { "XBS5_ILP32_OFFBIG_LINTFLAGS", _CS_XBS5_ILP32_OFFBIG_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_XBS5_LP64_OFF64
+ { "_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64, SYSCONF },
+#endif
+#ifdef _CS_XBS5_LP64_OFF64_CFLAGS
+ { "XBS5_LP64_OFF64_CFLAGS", _CS_XBS5_LP64_OFF64_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LP64_OFF64_LDFLAGS
+ { "XBS5_LP64_OFF64_LDFLAGS", _CS_XBS5_LP64_OFF64_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LP64_OFF64_LIBS
+ { "XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LP64_OFF64_LINTFLAGS
+ { "XBS5_LP64_OFF64_LINTFLAGS", _CS_XBS5_LP64_OFF64_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_XBS5_LPBIG_OFFBIG
+ { "_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG, SYSCONF },
+#endif
+#ifdef _CS_XBS5_LPBIG_OFFBIG_CFLAGS
+ { "XBS5_LPBIG_OFFBIG_CFLAGS", _CS_XBS5_LPBIG_OFFBIG_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LPBIG_OFFBIG_LDFLAGS
+ { "XBS5_LPBIG_OFFBIG_LDFLAGS", _CS_XBS5_LPBIG_OFFBIG_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LPBIG_OFFBIG_LIBS
+ { "XBS5_LPBIG_OFFBIG_LIBS", _CS_XBS5_LPBIG_OFFBIG_LIBS, CONFSTR },
+#endif
+#ifdef _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS
+ { "XBS5_LPBIG_OFFBIG_LINTFLAGS", _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_V6_ILP32_OFF32
+ { "_POSIX_V6_ILP32_OFF32", _SC_V6_ILP32_OFF32, SYSCONF },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFF32_CFLAGS
+ { "POSIX_V6_ILP32_OFF32_CFLAGS", _CS_POSIX_V6_ILP32_OFF32_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
+ { "POSIX_V6_ILP32_OFF32_LDFLAGS", _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFF32_LIBS
+ { "POSIX_V6_ILP32_OFF32_LIBS", _CS_POSIX_V6_ILP32_OFF32_LIBS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS
+ { "POSIX_V6_ILP32_OFF32_LINTFLAGS", _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _CS_V6_WIDTH_RESTRICTED_ENVS
+ { "_POSIX_V6_WIDTH_RESTRICTED_ENVS", _CS_V6_WIDTH_RESTRICTED_ENVS, CONFSTR },
+#endif
+
+#ifdef _SC_V6_ILP32_OFFBIG
+ { "_POSIX_V6_ILP32_OFFBIG", _SC_V6_ILP32_OFFBIG, SYSCONF },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
+ { "POSIX_V6_ILP32_OFFBIG_CFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
+ { "POSIX_V6_ILP32_OFFBIG_LDFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFFBIG_LIBS
+ { "POSIX_V6_ILP32_OFFBIG_LIBS", _CS_POSIX_V6_ILP32_OFFBIG_LIBS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS
+ { "POSIX_V6_ILP32_OFFBIG_LINTFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_V6_LP64_OFF64
+ { "_POSIX_V6_LP64_OFF64", _SC_V6_LP64_OFF64, SYSCONF },
+#endif
+#ifdef _CS_POSIX_V6_LP64_OFF64_CFLAGS
+ { "POSIX_V6_LP64_OFF64_CFLAGS", _CS_POSIX_V6_LP64_OFF64_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LP64_OFF64_LDFLAGS
+ { "POSIX_V6_LP64_OFF64_LDFLAGS", _CS_POSIX_V6_LP64_OFF64_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LP64_OFF64_LIBS
+ { "POSIX_V6_LP64_OFF64_LIBS", _CS_POSIX_V6_LP64_OFF64_LIBS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LP64_OFF64_LINTFLAGS
+ { "POSIX_V6_LP64_OFF64_LINTFLAGS", _CS_POSIX_V6_LP64_OFF64_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_V6_LPBIG_OFFBIG
+ { "_POSIX_V6_LPBIG_OFFBIG", _SC_V6_LPBIG_OFFBIG, SYSCONF },
+#endif
+#ifdef _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
+ { "POSIX_V6_LPBIG_OFFBIG_CFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+ { "POSIX_V6_LPBIG_OFFBIG_LDFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
+ { "POSIX_V6_LPBIG_OFFBIG_LIBS", _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, CONFSTR },
+#endif
+#ifdef _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS
+ { "POSIX_V6_LPBIG_OFFBIG_LINTFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS, CONFSTR },
+#endif
+
+#ifdef _SC_ADVISORY_INFO
+ { "_POSIX_ADVISORY_INFO", _SC_ADVISORY_INFO, SYSCONF },
+#endif
+#ifdef _SC_BARRIERS
+ { "_POSIX_BARRIERS", _SC_BARRIERS, SYSCONF },
+#endif
+#ifdef _SC_BASE
+ { "_POSIX_BASE", _SC_BASE, SYSCONF },
+#endif
+#ifdef _SC_C_LANG_SUPPORT
+ { "_POSIX_C_LANG_SUPPORT", _SC_C_LANG_SUPPORT, SYSCONF },
+#endif
+#ifdef _SC_C_LANG_SUPPORT_R
+ { "_POSIX_C_LANG_SUPPORT_R", _SC_C_LANG_SUPPORT_R, SYSCONF },
+#endif
+#ifdef _SC_CLOCK_SELECTION
+ { "_POSIX_CLOCK_SELECTION", _SC_CLOCK_SELECTION, SYSCONF },
+#endif
+#ifdef _SC_CPUTIME
+ { "_POSIX_CPUTIME", _SC_CPUTIME, SYSCONF },
+#endif
+#ifdef _SC_THREAD_CPUTIME
+ { "_POSIX_THREAD_CPUTIME", _SC_THREAD_CPUTIME, SYSCONF },
+#endif
+#ifdef _SC_DEVICE_SPECIFIC
+ { "_POSIX_DEVICE_SPECIFIC", _SC_DEVICE_SPECIFIC, SYSCONF },
+#endif
+#ifdef _SC_DEVICE_SPECIFIC_R
+ { "_POSIX_DEVICE_SPECIFIC_R", _SC_DEVICE_SPECIFIC_R, SYSCONF },
+#endif
+#ifdef _SC_FD_MGMT
+ { "_POSIX_FD_MGMT", _SC_FD_MGMT, SYSCONF },
+#endif
+#ifdef _SC_FIFO
+ { "_POSIX_FIFO", _SC_FIFO, SYSCONF },
+#endif
+#ifdef _SC_PIPE
+ { "_POSIX_PIPE", _SC_PIPE, SYSCONF },
+#endif
+#ifdef _SC_FILE_ATTRIBUTES
+ { "_POSIX_FILE_ATTRIBUTES", _SC_FILE_ATTRIBUTES, SYSCONF },
+#endif
+#ifdef _SC_FILE_LOCKING
+ { "_POSIX_FILE_LOCKING", _SC_FILE_LOCKING, SYSCONF },
+#endif
+#ifdef _SC_FILE_SYSTEM
+ { "_POSIX_FILE_SYSTEM", _SC_FILE_SYSTEM, SYSCONF },
+#endif
+#ifdef _SC_MONOTONIC_CLOCK
+ { "_POSIX_MONOTONIC_CLOCK", _SC_MONOTONIC_CLOCK, SYSCONF },
+#endif
+#ifdef _SC_MULTI_PROCESS
+ { "_POSIX_MULTI_PROCESS", _SC_MULTI_PROCESS, SYSCONF },
+#endif
+#ifdef _SC_SINGLE_PROCESS
+ { "_POSIX_SINGLE_PROCESS", _SC_SINGLE_PROCESS, SYSCONF },
+#endif
+#ifdef _SC_NETWORKING
+ { "_POSIX_NETWORKING", _SC_NETWORKING, SYSCONF },
+#endif
+#ifdef _SC_READER_WRITER_LOCKS
+ { "_POSIX_READER_WRITER_LOCKS", _SC_READER_WRITER_LOCKS, SYSCONF },
+#endif
+#ifdef _SC_SPIN_LOCKS
+ { "_POSIX_SPIN_LOCKS", _SC_SPIN_LOCKS, SYSCONF },
+#endif
+#ifdef _SC_REGEXP
+ { "_POSIX_REGEXP", _SC_REGEXP, SYSCONF },
+#endif
+#ifdef _SC_REGEX_VERSION
+ { "_REGEX_VERSION", _SC_REGEX_VERSION, SYSCONF },
+#endif
+#ifdef _SC_SHELL
+ { "_POSIX_SHELL", _SC_SHELL, SYSCONF },
+#endif
+#ifdef _SC_SIGNALS
+ { "_POSIX_SIGNALS", _SC_SIGNALS, SYSCONF },
+#endif
+#ifdef _SC_SPAWN
+ { "_POSIX_SPAWN", _SC_SPAWN, SYSCONF },
+#endif
+#ifdef _SC_SPORADIC_SERVER
+ { "_POSIX_SPORADIC_SERVER", _SC_SPORADIC_SERVER, SYSCONF },
+#endif
+#ifdef _SC_THREAD_SPORADIC_SERVER
+ { "_POSIX_THREAD_SPORADIC_SERVER", _SC_THREAD_SPORADIC_SERVER, SYSCONF },
+#endif
+#ifdef _SC_SYSTEM_DATABASE
+ { "_POSIX_SYSTEM_DATABASE", _SC_SYSTEM_DATABASE, SYSCONF },
+#endif
+#ifdef _SC_SYSTEM_DATABASE_R
+ { "_POSIX_SYSTEM_DATABASE_R", _SC_SYSTEM_DATABASE_R, SYSCONF },
+#endif
+#ifdef _SC_TIMEOUTS
+ { "_POSIX_TIMEOUTS", _SC_TIMEOUTS, SYSCONF },
+#endif
+#ifdef _SC_TYPED_MEMORY_OBJECTS
+ { "_POSIX_TYPED_MEMORY_OBJECTS", _SC_TYPED_MEMORY_OBJECTS, SYSCONF },
+#endif
+#ifdef _SC_USER_GROUPS
+ { "_POSIX_USER_GROUPS", _SC_USER_GROUPS, SYSCONF },
+#endif
+#ifdef _SC_USER_GROUPS_R
+ { "_POSIX_USER_GROUPS_R", _SC_USER_GROUPS_R, SYSCONF },
+#endif
+#ifdef _SC_2_PBS
+ { "POSIX2_PBS", _SC_2_PBS, SYSCONF },
+#endif
+#ifdef _SC_2_PBS_ACCOUNTING
+ { "POSIX2_PBS_ACCOUNTING", _SC_2_PBS_ACCOUNTING, SYSCONF },
+#endif
+#ifdef _SC_2_PBS_LOCATE
+ { "POSIX2_PBS_LOCATE", _SC_2_PBS_LOCATE, SYSCONF },
+#endif
+#ifdef _SC_2_PBS_TRACK
+ { "POSIX2_PBS_TRACK", _SC_2_PBS_TRACK, SYSCONF },
+#endif
+#ifdef _SC_2_PBS_MESSAGE
+ { "POSIX2_PBS_MESSAGE", _SC_2_PBS_MESSAGE, SYSCONF },
+#endif
+#ifdef _SC_SYMLOOP_MAX
+ { "SYMLOOP_MAX", _SC_SYMLOOP_MAX, SYSCONF },
+#endif
+#ifdef _SC_STREAM_MAX
+ { "STREAM_MAX", _SC_STREAM_MAX, SYSCONF },
+#endif
+#ifdef _SC_AIO_LISTIO_MAX
+ { "AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX, SYSCONF },
+#endif
+#ifdef _SC_AIO_MAX
+ { "AIO_MAX", _SC_AIO_MAX, SYSCONF },
+#endif
+#ifdef _SC_AIO_PRIO_DELTA_MAX
+ { "AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX, SYSCONF },
+#endif
+#ifdef _SC_DELAYTIMER_MAX
+ { "DELAYTIMER_MAX", _SC_DELAYTIMER_MAX, SYSCONF },
+#endif
+#ifdef _SC_HOST_NAME_MAX
+ { "HOST_NAME_MAX", _SC_HOST_NAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_LOGIN_NAME_MAX
+ { "LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX, SYSCONF },
+#endif
+#ifdef _SC_MQ_OPEN_MAX
+ { "MQ_OPEN_MAX", _SC_MQ_OPEN_MAX, SYSCONF },
+#endif
+#ifdef _SC_MQ_PRIO_MAX
+ { "MQ_PRIO_MAX", _SC_MQ_PRIO_MAX, SYSCONF },
+#endif
+#ifdef _SC_DEVICE_IO
+ { "_POSIX_DEVICE_IO", _SC_DEVICE_IO, SYSCONF },
+#endif
+#ifdef _SC_TRACE
+ { "_POSIX_TRACE", _SC_TRACE, SYSCONF },
+#endif
+#ifdef _SC_TRACE_EVENT_FILTER
+ { "_POSIX_TRACE_EVENT_FILTER", _SC_TRACE_EVENT_FILTER, SYSCONF },
+#endif
+#ifdef _SC_TRACE_INHERIT
+ { "_POSIX_TRACE_INHERIT", _SC_TRACE_INHERIT, SYSCONF },
+#endif
+#ifdef _SC_TRACE_LOG
+ { "_POSIX_TRACE_LOG", _SC_TRACE_LOG, SYSCONF },
+#endif
+#ifdef _SC_RTSIG_MAX
+ { "RTSIG_MAX", _SC_RTSIG_MAX, SYSCONF },
+#endif
+#ifdef _SC_SEM_NSEMS_MAX
+ { "SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX, SYSCONF },
+#endif
+#ifdef _SC_SEM_VALUE_MAX
+ { "SEM_VALUE_MAX", _SC_SEM_VALUE_MAX, SYSCONF },
+#endif
+#ifdef _SC_SIGQUEUE_MAX
+ { "SIGQUEUE_MAX", _SC_SIGQUEUE_MAX, SYSCONF },
+#endif
+#ifdef _PC_FILESIZEBITS
+ { "FILESIZEBITS", _PC_FILESIZEBITS, PATHCONF },
+#endif
+#ifdef _PC_ALLOC_SIZE_MIN
+ { "POSIX_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN, PATHCONF },
+#endif
+#ifdef _PC_REC_INCR_XFER_SIZE
+ { "POSIX_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE, PATHCONF },
+#endif
+#ifdef _PC_REC_MAX_XFER_SIZE
+ { "POSIX_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE, PATHCONF },
+#endif
+#ifdef _PC_REC_MIN_XFER_SIZE
+ { "POSIX_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE, PATHCONF },
+#endif
+#ifdef _PC_REC_XFER_ALIGN
+ { "POSIX_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN, PATHCONF },
+#endif
+#ifdef _PC_SYMLINK_MAX
+ { "SYMLINK_MAX", _PC_SYMLINK_MAX, PATHCONF },
+#endif
+#ifdef _CS_GNU_LIBC_VERSION
+ { "GNU_LIBC_VERSION", _CS_GNU_LIBC_VERSION, CONFSTR },
+#endif
+#ifdef _CS_GNU_LIBPTHREAD_VERSION
+ { "GNU_LIBPTHREAD_VERSION", _CS_GNU_LIBPTHREAD_VERSION, CONFSTR },
+#endif
+#ifdef _PC_2_SYMLINKS
+ { "POSIX2_SYMLINKS", _PC_2_SYMLINKS, PATHCONF },
+#endif
+
+#ifdef _SC_LEVEL1_ICACHE_SIZE
+ { "LEVEL1_ICACHE_SIZE", _SC_LEVEL1_ICACHE_SIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL1_ICACHE_ASSOC
+ { "LEVEL1_ICACHE_ASSOC", _SC_LEVEL1_ICACHE_ASSOC, SYSCONF },
+#endif
+#ifdef _SC_LEVEL1_ICACHE_LINESIZE
+ { "LEVEL1_ICACHE_LINESIZE", _SC_LEVEL1_ICACHE_LINESIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL1_DCACHE_SIZE
+ { "LEVEL1_DCACHE_SIZE", _SC_LEVEL1_DCACHE_SIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL1_DCACHE_ASSOC
+ { "LEVEL1_DCACHE_ASSOC", _SC_LEVEL1_DCACHE_ASSOC, SYSCONF },
+#endif
+#ifdef _SC_LEVEL1_DCACHE_LINESIZE
+ { "LEVEL1_DCACHE_LINESIZE", _SC_LEVEL1_DCACHE_LINESIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL2_CACHE_SIZE
+ { "LEVEL2_CACHE_SIZE", _SC_LEVEL2_CACHE_SIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL2_CACHE_ASSOC
+ { "LEVEL2_CACHE_ASSOC", _SC_LEVEL2_CACHE_ASSOC, SYSCONF },
+#endif
+#ifdef _SC_LEVEL2_CACHE_LINESIZE
+ { "LEVEL2_CACHE_LINESIZE", _SC_LEVEL2_CACHE_LINESIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL3_CACHE_SIZE
+ { "LEVEL3_CACHE_SIZE", _SC_LEVEL3_CACHE_SIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL3_CACHE_ASSOC
+ { "LEVEL3_CACHE_ASSOC", _SC_LEVEL3_CACHE_ASSOC, SYSCONF },
+#endif
+#ifdef _SC_LEVEL3_CACHE_LINESIZE
+ { "LEVEL3_CACHE_LINESIZE", _SC_LEVEL3_CACHE_LINESIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL4_CACHE_SIZE
+ { "LEVEL4_CACHE_SIZE", _SC_LEVEL4_CACHE_SIZE, SYSCONF },
+#endif
+#ifdef _SC_LEVEL4_CACHE_ASSOC
+ { "LEVEL4_CACHE_ASSOC", _SC_LEVEL4_CACHE_ASSOC, SYSCONF },
+#endif
+
+#ifdef _SC_IPV6
+ { "IPV6", _SC_IPV6, SYSCONF },
+#endif
+#ifdef _SC_RAW_SOCKETS
+ { "RAW_SOCKETS", _SC_RAW_SOCKETS, SYSCONF },
+#endif
+
+ { NULL, 0, SYSCONF }
+ };
+
+
+static struct { const char *name; int num; } specs[] =
+ {
+ { "POSIX_V6_ILP32_OFF32", _SC_V6_ILP32_OFF32 },
+ { "POSIX_V6_ILP32_OFFBIG", _SC_V6_ILP32_OFFBIG },
+ { "POSIX_V6_LP64_OFF64", _SC_V6_LP64_OFF64 },
+ { "POSIX_V6_LPBIG_OFFBIG", _SC_V6_LPBIG_OFFBIG }
+ };
+static const int nspecs = sizeof (specs) / sizeof (specs[0]);
+
+extern const char *__progname;
+
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ _("Usage: %s [-v specification] variable_name [pathname]\n"),
+ __progname);
+ fprintf (stderr,
+ _(" %s -a [pathname]\n"), __progname);
+ exit (2);
+}
+
+static void
+print_all (const char *path)
+{
+ register const struct conf *c;
+ size_t clen;
+ long int value;
+ char *cvalue;
+ for (c = vars; c->name != NULL; ++c) {
+ printf("%-35s", c->name);
+ switch (c->call) {
+ case PATHCONF:
+ value = pathconf (path, c->call_name);
+ if (value != -1) {
+ printf("%ld", value);
+ }
+ printf("\n");
+ break;
+ case SYSCONF:
+ value = sysconf (c->call_name);
+ if (value == -1l) {
+ if (c->call_name == _SC_UINT_MAX
+ || c->call_name == _SC_ULONG_MAX)
+ printf ("%lu", value);
+ }
+ else {
+ printf ("%ld", value);
+ }
+ printf ("\n");
+ break;
+ case CONFSTR:
+ clen = confstr (c->call_name, (char *) NULL, 0);
+ cvalue = (char *) malloc (clen);
+ if (cvalue == NULL)
+ error (3, 0, _("memory exhausted"));
+ if (confstr (c->call_name, cvalue, clen) != clen)
+ error (3, errno, "confstr");
+ printf ("%.*s\n", (int) clen, cvalue);
+ free (cvalue);
+ break;
+ }
+ }
+ exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ register const struct conf *c;
+
+ /* Set locale. Do not set LC_ALL because the other categories must
+ not be affected (according to POSIX.2). */
+ setlocale (LC_CTYPE, "");
+ setlocale (LC_MESSAGES, "");
+
+ /* Initialize the message catalog. */
+ textdomain (PACKAGE);
+
+ if (argc > 1 && strcmp (argv[1], "--version") == 0)
+ {
+ fprintf (stderr, "getconf (GNU %s) %s\n", PACKAGE, VERSION);
+ fprintf (stderr, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2006");
+ fprintf (stderr, gettext ("Written by %s.\n"), "Roland McGrath");
+ return 0;
+ }
+
+ const char *getconf_dir = getenv ("GETCONF_DIR") ?: GETCONF_DIR;
+ size_t getconf_dirlen = strlen (getconf_dir);
+
+ const char *spec = NULL;
+ char buf[sizeof "POSIX_V6_LPBIG_OFFBIG"];
+ char *argv0 = argv[0];
+ if (argc > 1 && strncmp (argv[1], "-v", 2) == 0)
+ {
+ if (argv[1][2] == '\0')
+ {
+ if (argc < 3)
+ usage ();
+
+ spec = argv[2];
+ argv += 2;
+ argc -= 2;
+ }
+ else
+ {
+ spec = &argv[1][2];
+ argv += 1;
+ argc += 1;
+ }
+ }
+ else
+ {
+ char default_name[getconf_dirlen + sizeof "/default"];
+ memcpy (mempcpy (default_name, getconf_dir, getconf_dirlen),
+ "/default", sizeof "/default");
+ int len = readlink (default_name, buf, sizeof buf - 1);
+ if (len > 0)
+ {
+ buf[len] = '\0';
+ spec = buf;
+ }
+ }
+
+ /* Check for the specifications we know. */
+ if (spec != NULL)
+ {
+ int i;
+ for (i = 0; i < nspecs; ++i)
+ if (strcmp (spec, specs[i].name) == 0)
+ break;
+
+ if (i == nspecs)
+ error (2, 0, _("unknown specification \"%s\""), spec);
+
+ switch (specs[i].num)
+ {
+#ifndef _POSIX_V6_ILP32_OFF32
+ case _SC_V6_ILP32_OFF32:
+#endif
+#ifndef _POSIX_V6_ILP32_OFFBIG
+ case _SC_V6_ILP32_OFFBIG:
+#endif
+#ifndef _POSIX_V6_LP64_OFF64
+ case _SC_V6_LP64_OFF64:
+#endif
+#ifndef _POSIX_V6_LPBIG_OFFBIG
+ case _SC_V6_LPBIG_OFFBIG:
+#endif
+ {
+ const char *args[argc + 3];
+ size_t spec_len = strlen (spec);
+ char getconf_name[getconf_dirlen + 1 + spec_len + 1];
+ memcpy (mempcpy (mempcpy (getconf_name, getconf_dir,
+ getconf_dirlen),
+ "/", 1), spec, spec_len + 1);
+ args[0] = argv0;
+ args[1] = "-v";
+ args[2] = spec;
+ memcpy (&args[3], &argv[1], argc * sizeof (argv[1]));
+ execv (getconf_name, (char * const *) args);
+ error (4, errno, _("Couldn't execute %s"), getconf_name);
+ }
+ default:
+ break;
+ }
+ }
+
+ if (argc > 1 && strcmp (argv[1], "-a") == 0)
+ {
+ if (argc == 2)
+ print_all ("/");
+ else if (argc == 3)
+ print_all (argv[2]);
+ else
+ usage ();
+ }
+
+ if (argc < 2 || argc > 3)
+ usage ();
+
+ for (c = vars; c->name != NULL; ++c)
+ if (strcmp (c->name, argv[1]) == 0
+ || (strncmp (c->name, "_POSIX_", 7) == 0
+ && strcmp (c->name + 7, argv[1]) == 0))
+ {
+ long int value;
+ size_t clen;
+ char *cvalue;
+ switch (c->call)
+ {
+ case PATHCONF:
+ if (argc < 3)
+ usage ();
+ errno = 0;
+ value = pathconf (argv[2], c->call_name);
+ if (value == -1)
+ {
+ if (errno)
+ error (3, errno, "pathconf: %s", argv[2]);
+ else
+ puts (_("undefined"));
+ }
+ else
+ printf ("%ld\n", value);
+ exit (0);
+
+ case SYSCONF:
+ if (argc > 2)
+ usage ();
+ value = sysconf (c->call_name);
+ if (value == -1l)
+ {
+ if (c->call_name == _SC_UINT_MAX
+ || c->call_name == _SC_ULONG_MAX)
+ printf ("%lu\n", value);
+ else
+ puts (_("undefined"));
+ }
+ else
+ printf ("%ld\n", value);
+ exit (0);
+
+ case CONFSTR:
+ if (argc > 2)
+ usage ();
+ clen = confstr (c->call_name, (char *) NULL, 0);
+ cvalue = (char *) malloc (clen);
+ if (cvalue == NULL)
+ error (3, 0, _("memory exhausted"));
+
+ if (confstr (c->call_name, cvalue, clen) != clen)
+ error (3, errno, "confstr");
+
+ printf ("%.*s\n", (int) clen, cvalue);
+ exit (0);
+ }
+ }
+
+ error (2, 0, _("Unrecognized variable `%s'"), argv[1]);
+ /* NOTREACHED */
+ return 2;
+}
diff --git a/libc/posix/getegid.c b/libc/posix/getegid.c
new file mode 100644
index 000000000..d939d6ad6
--- /dev/null
+++ b/libc/posix/getegid.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Get the effective group ID of the calling process. */
+__gid_t
+__getegid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getegid)
+
+weak_alias (__getegid, getegid)
+#include <stub-tag.h>
diff --git a/libc/posix/geteuid.c b/libc/posix/geteuid.c
new file mode 100644
index 000000000..c67dbfd70
--- /dev/null
+++ b/libc/posix/geteuid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Get the effective user ID of the calling process. */
+__uid_t
+__geteuid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (geteuid)
+
+weak_alias (__geteuid, geteuid)
+#include <stub-tag.h>
diff --git a/libc/posix/getgid.c b/libc/posix/getgid.c
new file mode 100644
index 000000000..742c099fa
--- /dev/null
+++ b/libc/posix/getgid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Get the real group ID of the calling process. */
+gid_t
+__getgid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getgid)
+
+weak_alias (__getgid, getgid)
+#include <stub-tag.h>
diff --git a/libc/posix/getgroups.c b/libc/posix/getgroups.c
new file mode 100644
index 000000000..d5868cc1b
--- /dev/null
+++ b/libc/posix/getgroups.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 1991,1992,1995,1996,1997,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+
+/* If SIZE is zero, return the number of supplementary groups
+ the calling process is in. Otherwise, fill in the group IDs
+ of its supplementary groups in LIST and return the number written. */
+int
+__getgroups (size, list)
+ int size;
+ gid_t *list;
+{
+#if defined (NGROUPS_MAX) && NGROUPS_MAX == 0
+ /* The system has no supplementary groups. */
+ return 0;
+#endif
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+#if !(defined (NGROUPS_MAX) && NGROUPS_MAX == 0)
+stub_warning (getgroups);
+#endif
+
+weak_alias (__getgroups, getgroups)
+#include <stub-tag.h>
diff --git a/libc/posix/getlogin.c b/libc/posix/getlogin.c
new file mode 100644
index 000000000..12b428339
--- /dev/null
+++ b/libc/posix/getlogin.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* Return the login name of the user, or NULL if it can't be determined.
+ The returned pointer, if not NULL, is good only until the next call. */
+char *
+getlogin (void)
+{
+ __set_errno (ENOSYS);
+ return NULL;
+}
+
+stub_warning (getlogin)
+#include <stub-tag.h>
diff --git a/libc/posix/getlogin_r.c b/libc/posix/getlogin_r.c
new file mode 100644
index 000000000..f2470ee03
--- /dev/null
+++ b/libc/posix/getlogin_r.c
@@ -0,0 +1,37 @@
+/* Reentrant function to return the current login name. Stub version.
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Return at most NAME_LEN characters of the login name of the user in NAME.
+ If it cannot be determined or some other error occurred, return the error
+ code. Otherwise return 0. */
+int
+getlogin_r (name, name_len)
+ char *name;
+ size_t name_len;
+{
+ __set_errno (ENOSYS);
+ return errno;
+}
+libc_hidden_def (getlogin_r)
+
+stub_warning (getlogin_r)
+#include <stub-tag.h>
diff --git a/libc/posix/getopt.c b/libc/posix/getopt.c
new file mode 100644
index 000000000..b1cecd31a
--- /dev/null
+++ b/libc/posix/getopt.c
@@ -0,0 +1,1225 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
+ before changing it!
+ Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#include <string.h>
+
+#ifdef VMS
+# include <unixlib.h>
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "gettext.h"
+# define _(msgid) gettext (msgid)
+#endif
+
+#if defined _LIBC && defined USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+#include "getopt_int.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Keep a global copy of all internal members of getopt_data. */
+
+static struct _getopt_data getopt_data;
+
+
+#ifndef __GNU_LIBRARY__
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+#endif /* not __GNU_LIBRARY__ */
+
+#ifdef _LIBC
+/* Stored original parameters.
+ XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+extern int __libc_argc;
+extern char **__libc_argv;
+
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+# ifdef USE_NONOPTION_FLAGS
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+# endif
+
+# ifdef USE_NONOPTION_FLAGS
+# define SWAP_FLAGS(ch1, ch2) \
+ if (d->__nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+# else
+# define SWAP_FLAGS(ch1, ch2)
+# endif
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (char **argv, struct _getopt_data *d)
+{
+ int bottom = d->__first_nonopt;
+ int middle = d->__last_nonopt;
+ int top = d->optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ d->__nonoption_flags_max_len),
+ '\0', top + 1 - d->__nonoption_flags_max_len);
+ d->__nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ d->__first_nonopt += (d->optind - d->__last_nonopt);
+ d->__last_nonopt = d->optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (int argc, char *const *argv, const char *optstring,
+ struct _getopt_data *d)
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ d->__first_nonopt = d->__last_nonopt = d->optind;
+
+ d->__nextchar = NULL;
+
+ d->__posixly_correct = !!getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ d->__ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ d->__ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (d->__posixly_correct)
+ d->__ordering = REQUIRE_ORDER;
+ else
+ d->__ordering = PERMUTE;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ if (!d->__posixly_correct
+ && argc == __libc_argc && argv == __libc_argv)
+ {
+ if (d->__nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ d->__nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = d->__nonoption_flags_max_len = strlen (orig_str);
+ if (d->__nonoption_flags_max_len < argc)
+ d->__nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (d->__nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ d->__nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', d->__nonoption_flags_max_len - len);
+ }
+ }
+ d->__nonoption_flags_len = d->__nonoption_flags_max_len;
+ }
+ else
+ d->__nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal_r (int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longind,
+ int long_only, struct _getopt_data *d)
+{
+ int print_errors = d->opterr;
+ if (optstring[0] == ':')
+ print_errors = 0;
+
+ if (argc < 1)
+ return -1;
+
+ d->optarg = NULL;
+
+ if (d->optind == 0 || !d->__initialized)
+ {
+ if (d->optind == 0)
+ d->optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring, d);
+ d->__initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \
+ || (d->optind < d->__nonoption_flags_len \
+ && __getopt_nonoption_flags[d->optind] == '1'))
+#else
+# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')
+#endif
+
+ if (d->__nextchar == NULL || *d->__nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (d->__last_nonopt > d->optind)
+ d->__last_nonopt = d->optind;
+ if (d->__first_nonopt > d->optind)
+ d->__first_nonopt = d->optind;
+
+ if (d->__ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (d->__first_nonopt != d->__last_nonopt
+ && d->__last_nonopt != d->optind)
+ exchange ((char **) argv, d);
+ else if (d->__last_nonopt != d->optind)
+ d->__first_nonopt = d->optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (d->optind < argc && NONOPTION_P)
+ d->optind++;
+ d->__last_nonopt = d->optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (d->optind != argc && !strcmp (argv[d->optind], "--"))
+ {
+ d->optind++;
+
+ if (d->__first_nonopt != d->__last_nonopt
+ && d->__last_nonopt != d->optind)
+ exchange ((char **) argv, d);
+ else if (d->__first_nonopt == d->__last_nonopt)
+ d->__first_nonopt = d->optind;
+ d->__last_nonopt = argc;
+
+ d->optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (d->optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (d->__first_nonopt != d->__last_nonopt)
+ d->optind = d->__first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (d->__ordering == REQUIRE_ORDER)
+ return -1;
+ d->optarg = argv[d->optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ d->__nextchar = (argv[d->optind] + 1
+ + (longopts != NULL && argv[d->optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[d->optind][1] == '-'
+ || (long_only && (argv[d->optind][2]
+ || !strchr (optstring, argv[d->optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
+ {
+ if ((unsigned int) (nameend - d->__nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else if (long_only
+ || pfound->has_arg != p->has_arg
+ || pfound->flag != p->flag
+ || pfound->val != p->val)
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[d->optind]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[d->optind]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optind++;
+ d->optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ d->optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ d->optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (argv[d->optind - 1][1] == '-')
+ {
+ /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#else
+ fprintf (stderr, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#endif
+ }
+ else
+ {
+ /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[d->optind - 1][0],
+ pfound->name);
+#else
+ fprintf (stderr, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[d->optind - 1][0],
+ pfound->name);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+
+ d->__nextchar += strlen (d->__nextchar);
+
+ d->optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (d->optind < argc)
+ d->optarg = argv[d->optind++];
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[d->optind][1] == '-'
+ || strchr (optstring, *d->__nextchar) == NULL)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (argv[d->optind][1] == '-')
+ {
+ /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"),
+ argv[0], d->__nextchar);
+#else
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], d->__nextchar);
+#endif
+ }
+ else
+ {
+ /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[d->optind][0], d->__nextchar);
+#else
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[d->optind][0], d->__nextchar);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+ d->__nextchar = (char *) "";
+ d->optind++;
+ d->optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *d->__nextchar++;
+ char *temp = strchr (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*d->__nextchar == '\0')
+ ++d->optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+ int n;
+#endif
+
+ if (d->__posixly_correct)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+#else
+ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c);
+#endif
+ }
+ else
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ n = __asprintf (&buf, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+#else
+ fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
+#endif
+ }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+ if (n >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#endif
+ }
+ d->optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ d->optind++;
+ }
+ else if (d->optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+#endif
+ }
+ d->optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `d->optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ d->optarg = argv[d->optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '=';
+ nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
+ {
+ if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[d->optind]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[d->optind]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ d->optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ d->optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+#endif
+ }
+
+ d->__nextchar += strlen (d->__nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (d->optind < argc)
+ d->optarg = argv[d->optind++];
+ else
+ {
+ if (print_errors)
+ {
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2
+ |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[d->optind - 1]);
+#endif
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ d->__nextchar += strlen (d->__nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ d->__nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ d->optind++;
+ }
+ else
+ d->optarg = NULL;
+ d->__nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*d->__nextchar != '\0')
+ {
+ d->optarg = d->__nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ d->optind++;
+ }
+ else if (d->optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+#if defined _LIBC && defined USE_IN_LIBIO
+ char *buf;
+
+ if (__asprintf (&buf, _("\
+%s: option requires an argument -- %c\n"),
+ argv[0], c) >= 0)
+ {
+ _IO_flockfile (stderr);
+
+ int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+ ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+
+ __fxprintf (NULL, "%s", buf);
+
+ ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+ _IO_funlockfile (stderr);
+
+ free (buf);
+ }
+#else
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+#endif
+ }
+ d->optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ d->optarg = argv[d->optind++];
+ d->__nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+_getopt_internal (int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longind, int long_only)
+{
+ int result;
+
+ getopt_data.optind = optind;
+ getopt_data.opterr = opterr;
+
+ result = _getopt_internal_r (argc, argv, optstring, longopts,
+ longind, long_only, &getopt_data);
+
+ optind = getopt_data.optind;
+ optarg = getopt_data.optarg;
+ optopt = getopt_data.optopt;
+
+ return result;
+}
+
+int
+getopt (int argc, char *const *argv, const char *optstring)
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/libc/posix/getopt.h b/libc/posix/getopt.h
new file mode 100644
index 000000000..b7a026c53
--- /dev/null
+++ b/libc/posix/getopt.h
@@ -0,0 +1,177 @@
+/* Declarations for getopt.
+ Copyright (C) 1989-1994,1996-1999,2001,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+/* If __GNU_LIBRARY__ is not already defined, either we are being used
+ standalone, or this is the first header included in the source file.
+ If we are being used with glibc, we need to include <features.h>, but
+ that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
+ not defined, include <ctype.h>, which will pull in <features.h> for us
+ if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
+ doesn't flood the namespace with stuff the way some other headers do.) */
+#if !defined __GNU_LIBRARY__
+# include <ctype.h>
+#endif
+
+#ifndef __THROW
+# ifndef __GNUC_PREREQ
+# define __GNUC_PREREQ(maj, min) (0)
+# endif
+# if defined __cplusplus && __GNUC_PREREQ (2,8)
+# define __THROW throw ()
+# else
+# define __THROW
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+ const char *name;
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+# define no_argument 0
+# define required_argument 1
+# define optional_argument 2
+#endif /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+ arguments in ARGV (ARGC of them, minus the program name) for
+ options given in OPTS.
+
+ Return the option character from OPTS just read. Return -1 when
+ there are no more options. For unrecognized options, or options
+ missing arguments, `optopt' is set to the option letter, and '?' is
+ returned.
+
+ The OPTS string is a list of characters which are recognized option
+ letters, optionally followed by colons, specifying that that letter
+ takes an argument, to be placed in `optarg'.
+
+ If a letter in OPTS is followed by two colons, its argument is
+ optional. This behavior is specific to the GNU `getopt'.
+
+ The argument `--' causes premature termination of argument
+ scanning, explicitly telling `getopt' that there are no more
+ options.
+
+ If OPTS begins with `--', then non-option arguments are treated as
+ arguments to the option '\0'. This behavior is specific to the GNU
+ `getopt'. */
+
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)
+ __THROW;
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+
+#ifndef __need_getopt
+extern int getopt_long (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind)
+ __THROW;
+extern int getopt_long_only (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind)
+ __THROW;
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations. */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/libc/posix/getopt1.c b/libc/posix/getopt1.c
new file mode 100644
index 000000000..2f75d4c2e
--- /dev/null
+++ b/libc/posix/getopt1.c
@@ -0,0 +1,192 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef _LIBC
+# include <getopt.h>
+#else
+# include "getopt.h"
+#endif
+#include "getopt_int.h"
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (int argc, char *const *argv, const char *options,
+ const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+int
+_getopt_long_r (int argc, char *const *argv, const char *options,
+ const struct option *long_options, int *opt_index,
+ struct _getopt_data *d)
+{
+ return _getopt_internal_r (argc, argv, options, long_options, opt_index,
+ 0, d);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (int argc, char *const *argv, const char *options,
+ const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+int
+_getopt_long_only_r (int argc, char *const *argv, const char *options,
+ const struct option *long_options, int *opt_index,
+ struct _getopt_data *d)
+{
+ return _getopt_internal_r (argc, argv, options, long_options, opt_index,
+ 1, d);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/libc/posix/getopt_init.c b/libc/posix/getopt_init.c
new file mode 100644
index 000000000..d460098c8
--- /dev/null
+++ b/libc/posix/getopt_init.c
@@ -0,0 +1,75 @@
+/* Perform additional initialization for getopt functions in GNU libc.
+ Copyright (C) 1997, 1998, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef USE_NONOPTION_FLAGS
+/* Attention: this file is *not* necessary when the GNU getopt functions
+ are used outside the GNU libc. Some additional functionality of the
+ getopt functions in GNU libc require this additional work. */
+
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <stdio-common/_itoa.h>
+
+/* Variable to synchronize work. */
+char *__getopt_nonoption_flags;
+
+
+/* Remove the environment variable "_<PID>_GNU_nonoption_argv_flags_" if
+ it is still available. If the getopt functions are also used in the
+ application it does not exist anymore since it was saved for the use
+ in getopt. */
+void
+__getopt_clean_environment (char **env)
+{
+ /* Bash 2.0 puts a special variable in the environment for each
+ command it runs, specifying which ARGV elements are the results
+ of file name wildcard expansion and therefore should not be
+ considered as options. */
+ static const char envvar_tail[] = "_GNU_nonoption_argv_flags_=";
+ char var[50];
+ char *cp, **ep;
+ size_t len;
+
+ /* Construct the "_<PID>_GNU_nonoption_argv_flags_=" string. We must
+ not use `sprintf'. */
+ cp = memcpy (&var[sizeof (var) - sizeof (envvar_tail)], envvar_tail,
+ sizeof (envvar_tail));
+ cp = _itoa_word (__getpid (), cp, 10, 0);
+ /* Note: we omit adding the leading '_' since we explicitly test for
+ it before calling strncmp. */
+ len = (var + sizeof (var) - 1) - cp;
+
+ for (ep = env; *ep != NULL; ++ep)
+ if ((*ep)[0] == '_'
+ && __builtin_expect (strncmp (*ep + 1, cp, len) == 0, 0))
+ {
+ /* Found it. Store this pointer and move later ones back. */
+ char **dp = ep;
+ __getopt_nonoption_flags = &(*ep)[len];
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case the name appears again. */
+ }
+}
+#endif /* USE_NONOPTION_FLAGS */
diff --git a/libc/posix/getopt_int.h b/libc/posix/getopt_int.h
new file mode 100644
index 000000000..d982c72d9
--- /dev/null
+++ b/libc/posix/getopt_int.h
@@ -0,0 +1,130 @@
+/* Internal declarations for getopt.
+ Copyright (C) 1989-1994,1996-1999,2001,2003,2004
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _GETOPT_INT_H
+#define _GETOPT_INT_H 1
+
+extern int _getopt_internal (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ int __long_only);
+
+
+/* Reentrant versions which can handle parsing multiple argument
+ vectors at the same time. */
+
+/* Data type for reentrant functions. */
+struct _getopt_data
+{
+ /* These have exactly the same meaning as the corresponding global
+ variables, except that they are used for the reentrant
+ versions of getopt. */
+ int optind;
+ int opterr;
+ int optopt;
+ char *optarg;
+
+ /* Internal members. */
+
+ /* True if the internal members have been initialized. */
+ int __initialized;
+
+ /* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+ char *__nextchar;
+
+ /* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we
+ scan, so that eventually all the non-options are at the end.
+ This allows options to be given in any order, even with programs
+ that were not written to expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were
+ written to expect options and other ARGV-elements in any order
+ and that care about the ordering of the two. We describe each
+ non-option ARGV-element as if it were the argument of an option
+ with character code 1. Using `-' as the first character of the
+ list of option characters selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+ enum
+ {
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+ } __ordering;
+
+ /* If the POSIXLY_CORRECT environment variable is set. */
+ int __posixly_correct;
+
+
+ /* Handle permutation of arguments. */
+
+ /* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first
+ of them; `last_nonopt' is the index after the last of them. */
+
+ int __first_nonopt;
+ int __last_nonopt;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ int __nonoption_flags_max_len;
+ int __nonoption_flags_len;
+# endif
+};
+
+/* The initializer is necessary to set OPTIND and OPTERR to their
+ default values and to clear the initialization flag. */
+#define _GETOPT_DATA_INITIALIZER { 1, 1 }
+
+extern int _getopt_internal_r (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ int __long_only, struct _getopt_data *__data);
+
+extern int _getopt_long_r (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ struct _getopt_data *__data);
+
+extern int _getopt_long_only_r (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts,
+ int *__longind,
+ struct _getopt_data *__data);
+
+#endif /* getopt_int.h */
diff --git a/libc/posix/getpgid.c b/libc/posix/getpgid.c
new file mode 100644
index 000000000..ad46771d2
--- /dev/null
+++ b/libc/posix/getpgid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991,1995,1996,1997,1998,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Get the process group ID of process PID. */
+pid_t
+__getpgid (pid)
+ pid_t pid;
+{
+ return pid;
+}
+libc_hidden_def (__getpgid)
+weak_alias (__getpgid, getpgid)
+
+stub_warning (getpgid)
+#include <stub-tag.h>
diff --git a/libc/posix/getpgrp.c b/libc/posix/getpgrp.c
new file mode 100644
index 000000000..85efc2f21
--- /dev/null
+++ b/libc/posix/getpgrp.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991, 1995, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Get the process group ID of the calling process. */
+pid_t
+getpgrp (void)
+{
+ return __getpgid (0);
+}
diff --git a/libc/posix/getpid.c b/libc/posix/getpid.c
new file mode 100644
index 000000000..c1c91fede
--- /dev/null
+++ b/libc/posix/getpid.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Get the process ID of the calling process. */
+int
+__getpid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__getpid)
+stub_warning (getpid)
+
+weak_alias (__getpid, getpid)
+libc_hidden_weak (getpid)
+#include <stub-tag.h>
diff --git a/libc/posix/getppid.c b/libc/posix/getppid.c
new file mode 100644
index 000000000..e00c23749
--- /dev/null
+++ b/libc/posix/getppid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Get the parent process ID of the calling process. */
+int
+__getppid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getppid)
+
+weak_alias (__getppid, getppid)
+#include <stub-tag.h>
diff --git a/libc/posix/getresgid.c b/libc/posix/getresgid.c
new file mode 100644
index 000000000..eccce7d69
--- /dev/null
+++ b/libc/posix/getresgid.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991,1995,1996,1997,1998,2002,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Fetch the real group ID, effective group ID, and saved-set group ID,
+ of the calling process. */
+int
+__getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__getresgid)
+stub_warning (getresgid)
+
+weak_alias (__getresgid, getresgid)
+#include <stub-tag.h>
diff --git a/libc/posix/getresuid.c b/libc/posix/getresuid.c
new file mode 100644
index 000000000..83456c29b
--- /dev/null
+++ b/libc/posix/getresuid.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991,1995,1996,1997,1998,2002,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Fetch the real user ID, effective user ID, and saved-set user ID,
+ of the calling process. */
+int
+__getresuid (uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__getresuid)
+stub_warning (getresuid)
+
+weak_alias (__getresuid, getresuid)
+#include <stub-tag.h>
diff --git a/libc/posix/getsid.c b/libc/posix/getsid.c
new file mode 100644
index 000000000..eb7e60fa4
--- /dev/null
+++ b/libc/posix/getsid.c
@@ -0,0 +1,32 @@
+/* getsid -- Return session ID of a process. Stub version.
+ Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+pid_t
+getsid (pid_t pid)
+{
+ __set_errno (ENOSYS);
+ return (pid_t) -1;
+}
+libc_hidden_def (getsid)
+stub_warning (getsid)
+#include <stub-tag.h>
diff --git a/libc/posix/getuid.c b/libc/posix/getuid.c
new file mode 100644
index 000000000..c4ea7e8c9
--- /dev/null
+++ b/libc/posix/getuid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Get the real user ID of the calling process. */
+uid_t
+__getuid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getuid)
+
+weak_alias (__getuid, getuid)
+#include <stub-tag.h>
diff --git a/libc/posix/glob.c b/libc/posix/glob.c
new file mode 100644
index 000000000..d2a9981e3
--- /dev/null
+++ b/libc/posix/glob.c
@@ -0,0 +1,1303 @@
+/* Copyright (C) 1991-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glob.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+/* Outcomment the following line for production quality code. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include <stdio.h> /* Needed on stupid SunOS for assert. */
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+# ifndef POSIX
+# ifdef _POSIX_VERSION
+# define POSIX
+# endif
+# endif
+#endif
+
+#include <pwd.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# ifdef HAVE_VMSDIR_H
+# include "vmsdir.h"
+# endif /* HAVE_VMSDIR_H */
+#endif
+
+
+/* In GNU systems, <dirent.h> defines this macro for us. */
+#ifdef _D_NAMLEN
+# undef NAMLEN
+# define NAMLEN(d) _D_NAMLEN(d)
+#endif
+
+/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+ if the `d_type' member for `struct dirent' is available.
+ HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+/* True if the directory entry D must be of type T. */
+# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t))
+
+/* True if the directory entry D might be a symbolic link. */
+# define DIRENT_MIGHT_BE_SYMLINK(d) \
+ ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+
+/* True if the directory entry D might be a directory. */
+# define DIRENT_MIGHT_BE_DIR(d) \
+ ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+
+#else /* !HAVE_D_TYPE */
+# define DIRENT_MUST_BE(d, t) false
+# define DIRENT_MIGHT_BE_SYMLINK(d) true
+# define DIRENT_MIGHT_BE_DIR(d) true
+#endif /* HAVE_D_TYPE */
+
+/* If the system has the `struct dirent64' type we use it internally. */
+#if defined _LIBC && !defined COMPILE_GLOB64
+# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+# define CONVERT_D_NAMLEN(d64, d32)
+# else
+# define CONVERT_D_NAMLEN(d64, d32) \
+ (d64)->d_namlen = (d32)->d_namlen;
+# endif
+
+# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+# define CONVERT_D_INO(d64, d32)
+# else
+# define CONVERT_D_INO(d64, d32) \
+ (d64)->d_ino = (d32)->d_ino;
+# endif
+
+# ifdef _DIRENT_HAVE_D_TYPE
+# define CONVERT_D_TYPE(d64, d32) \
+ (d64)->d_type = (d32)->d_type;
+# else
+# define CONVERT_D_TYPE(d64, d32)
+# endif
+
+# define CONVERT_DIRENT_DIRENT64(d64, d32) \
+ memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
+ CONVERT_D_NAMLEN (d64, d32) \
+ CONVERT_D_INO (d64, d32) \
+ CONVERT_D_TYPE (d64, d32)
+#endif
+
+
+#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+/* Posix does not require that the d_ino field be present, and some
+ systems do not provide it. */
+# define REAL_DIR_ENTRY(dp) 1
+#else
+# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+#endif /* POSIX */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* NAME_MAX is usually defined in <dirent.h> or <limits.h>. */
+#include <limits.h>
+#ifndef NAME_MAX
+# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name))
+#endif
+
+#include <alloca.h>
+
+#ifdef _LIBC
+# undef strdup
+# define strdup(str) __strdup (str)
+# define sysconf(id) __sysconf (id)
+# define closedir(dir) __closedir (dir)
+# define opendir(name) __opendir (name)
+# define readdir(str) __readdir64 (str)
+# define getpwnam_r(name, bufp, buf, len, res) \
+ __getpwnam_r (name, bufp, buf, len, res)
+# ifndef __stat64
+# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
+# endif
+# define struct_stat64 struct stat64
+#else /* !_LIBC */
+# include "getlogin_r.h"
+# include "mempcpy.h"
+# include "stat-macros.h"
+# include "strdup.h"
+# define __stat64(fname, buf) stat (fname, buf)
+# define struct_stat64 struct stat
+# define __stat(fname, buf) stat (fname, buf)
+# define __alloca alloca
+# define __readdir readdir
+# define __readdir64 readdir64
+# define __glob_pattern_p glob_pattern_p
+#endif /* _LIBC */
+
+#include <fnmatch.h>
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
+#else
+# define GETPW_R_SIZE_MAX() (-1)
+#endif
+#ifdef _SC_LOGIN_NAME_MAX
+# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
+#else
+# define GET_LOGIN_NAME_MAX() (-1)
+#endif
+
+static const char *next_brace_sub (const char *begin, int flags) __THROW;
+
+#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+
+static int glob_in_dir (const char *pattern, const char *directory,
+ int flags, int (*errfunc) (const char *, int),
+ glob_t *pglob);
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+static int prefix_array (const char *prefix, char **array, size_t n) __THROW;
+static int collated_compare (const void *, const void *) __THROW;
+
+
+/* Find the end of the sub-pattern in a brace expression. */
+static const char *
+next_brace_sub (const char *cp, int flags)
+{
+ unsigned int depth = 0;
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+ if (*++cp == '\0')
+ break;
+ ++cp;
+ }
+ else
+ {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
+
+ if (*cp++ == '{')
+ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+}
+
+#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+int
+#ifdef GLOB_ATTRIBUTE
+GLOB_ATTRIBUTE
+#endif
+glob (pattern, flags, errfunc, pglob)
+ const char *pattern;
+ int flags;
+ int (*errfunc) (const char *, int);
+ glob_t *pglob;
+{
+ const char *filename;
+ const char *dirname;
+ size_t dirlen;
+ int status;
+ size_t oldcount;
+
+ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ if (!(flags & GLOB_DOOFFS))
+ /* Have to do this so `globfree' knows where to start freeing. It
+ also makes all the code that uses gl_offs simpler. */
+ pglob->gl_offs = 0;
+
+ if (flags & GLOB_BRACE)
+ {
+ const char *begin;
+
+ if (flags & GLOB_NOESCAPE)
+ begin = strchr (pattern, '{');
+ else
+ {
+ begin = pattern;
+ while (1)
+ {
+ if (*begin == '\0')
+ {
+ begin = NULL;
+ break;
+ }
+
+ if (*begin == '\\' && begin[1] != '\0')
+ ++begin;
+ else if (*begin == '{')
+ break;
+
+ ++begin;
+ }
+ }
+
+ if (begin != NULL)
+ {
+ /* Allocate working buffer large enough for our work. Note that
+ we have at least an opening and closing brace. */
+ size_t firstc;
+ char *alt_start;
+ const char *p;
+ const char *next;
+ const char *rest;
+ size_t rest_len;
+#ifdef __GNUC__
+ char onealt[strlen (pattern) - 1];
+#else
+ char *onealt = (char *) malloc (strlen (pattern) - 1);
+ if (onealt == NULL)
+ {
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ return GLOB_NOSPACE;
+ }
+#endif
+
+ /* We know the prefix for all sub-patterns. */
+ alt_start = mempcpy (onealt, pattern, begin - pattern);
+
+ /* Find the first sub-pattern and at the same time find the
+ rest after the closing brace. */
+ next = next_brace_sub (begin + 1, flags);
+ if (next == NULL)
+ {
+ /* It is an illegal expression. */
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+
+ /* Now find the end of the whole brace expression. */
+ rest = next;
+ while (*rest != '}')
+ {
+ rest = next_brace_sub (rest + 1, flags);
+ if (rest == NULL)
+ {
+ /* It is an illegal expression. */
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+ }
+ /* Please note that we now can be sure the brace expression
+ is well-formed. */
+ rest_len = strlen (++rest) + 1;
+
+ /* We have a brace expression. BEGIN points to the opening {,
+ NEXT points past the terminator of the first element, and END
+ points past the final }. We will accumulate result names from
+ recursive runs for each brace alternative in the buffer using
+ GLOB_APPEND. */
+
+ if (!(flags & GLOB_APPEND))
+ {
+ /* This call is to set a new vector, so clear out the
+ vector so we can append to it. */
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ firstc = pglob->gl_pathc;
+
+ p = begin + 1;
+ while (1)
+ {
+ int result;
+
+ /* Construct the new glob expression. */
+ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+ result = glob (onealt,
+ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+ | GLOB_APPEND), errfunc, pglob);
+
+ /* If we got an error, return it. */
+ if (result && result != GLOB_NOMATCH)
+ {
+#ifndef __GNUC__
+ free (onealt);
+#endif
+ if (!(flags & GLOB_APPEND))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ }
+ return result;
+ }
+
+ if (*next == '}')
+ /* We saw the last entry. */
+ break;
+
+ p = next + 1;
+ next = next_brace_sub (p, flags);
+ assert (next != NULL);
+ }
+
+#ifndef __GNUC__
+ free (onealt);
+#endif
+
+ if (pglob->gl_pathc != firstc)
+ /* We found some entries. */
+ return 0;
+ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ return GLOB_NOMATCH;
+ }
+ }
+
+ /* Find the filename. */
+ filename = strrchr (pattern, '/');
+#if defined __MSDOS__ || defined WINDOWS32
+ /* The case of "d:pattern". Since `:' is not allowed in
+ file names, we can safely assume that wherever it
+ happens in pattern, it signals the filename part. This
+ is so we could some day support patterns like "[a-z]:foo". */
+ if (filename == NULL)
+ filename = strchr (pattern, ':');
+#endif /* __MSDOS__ || WINDOWS32 */
+ if (filename == NULL)
+ {
+ /* This can mean two things: a simple name or "~name". The latter
+ case is nothing but a notation for a directory. */
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+ {
+ dirname = pattern;
+ dirlen = strlen (pattern);
+
+ /* Set FILENAME to NULL as a special flag. This is ugly but
+ other solutions would require much more code. We test for
+ this special case below. */
+ filename = NULL;
+ }
+ else
+ {
+ filename = pattern;
+#ifdef _AMIGA
+ dirname = "";
+#else
+ dirname = ".";
+#endif
+ dirlen = 0;
+ }
+ }
+ else if (filename == pattern)
+ {
+ /* "/pattern". */
+ dirname = "/";
+ dirlen = 1;
+ ++filename;
+ }
+ else
+ {
+ char *newp;
+ dirlen = filename - pattern;
+#if defined __MSDOS__ || defined WINDOWS32
+ if (*filename == ':'
+ || (filename > pattern + 1 && filename[-1] == ':'))
+ {
+ char *drive_spec;
+
+ ++dirlen;
+ drive_spec = (char *) __alloca (dirlen + 1);
+ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+ /* For now, disallow wildcards in the drive spec, to
+ prevent infinite recursion in glob. */
+ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+ return GLOB_NOMATCH;
+ /* If this is "d:pattern", we need to copy `:' to DIRNAME
+ as well. If it's "d:/pattern", don't remove the slash
+ from "d:/", since "d:" and "d:/" are not the same.*/
+ }
+#endif
+ newp = (char *) __alloca (dirlen + 1);
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
+ ++filename;
+
+ if (filename[0] == '\0'
+#if defined __MSDOS__ || defined WINDOWS32
+ && dirname[dirlen - 1] != ':'
+ && (dirlen < 3 || dirname[dirlen - 2] != ':'
+ || dirname[dirlen - 1] != '/')
+#endif
+ && dirlen > 1)
+ /* "pattern/". Expand "pattern", appending slashes. */
+ {
+ int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+ if (val == 0)
+ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+ | (flags & GLOB_MARK));
+ return val;
+ }
+ }
+
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_pathv = NULL;
+ else
+ {
+ size_t i;
+ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
+ * sizeof (char *));
+ if (pglob->gl_pathv == NULL)
+ return GLOB_NOSPACE;
+
+ for (i = 0; i <= pglob->gl_offs; ++i)
+ pglob->gl_pathv[i] = NULL;
+ }
+ }
+
+ oldcount = pglob->gl_pathc + pglob->gl_offs;
+
+#ifndef VMS
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+ {
+ if (dirname[1] == '\0' || dirname[1] == '/')
+ {
+ /* Look up home directory. */
+ const char *home_dir = getenv ("HOME");
+# ifdef _AMIGA
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "SYS:";
+# else
+# ifdef WINDOWS32
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "c:/users/default"; /* poor default */
+# else
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+ char *name;
+ size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+
+ if (buflen == 0)
+ /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+ a moderate value. */
+ buflen = 20;
+ name = (char *) __alloca (buflen);
+
+ success = getlogin_r (name, buflen) == 0;
+ if (success)
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+# ifndef _LIBC
+ if (pwbuflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+ Try a moderate value. */
+ pwbuflen = 1024;
+# endif
+ pwtmpbuf = (char *) __alloca (pwbuflen);
+
+ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+ != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+# ifdef _LIBC
+ pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+ 2 * pwbuflen);
+# else
+ pwbuflen *= 2;
+ pwtmpbuf = (char *) __alloca (pwbuflen);
+# endif
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (name);
+# endif
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ }
+ }
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+ return GLOB_NOMATCH;
+ else
+ home_dir = "~"; /* No luck. */
+ }
+# endif /* WINDOWS32 */
+# endif
+ /* Now construct the full directory. */
+ if (dirname[1] == '\0')
+ dirname = home_dir;
+ else
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ newp = (char *) __alloca (home_len + dirlen);
+ mempcpy (mempcpy (newp, home_dir, home_len),
+ &dirname[1], dirlen);
+ dirname = newp;
+ }
+ }
+# if !defined _AMIGA && !defined WINDOWS32
+ else
+ {
+ char *end_name = strchr (dirname, '/');
+ const char *user_name;
+ const char *home_dir;
+
+ if (end_name == NULL)
+ user_name = dirname + 1;
+ else
+ {
+ char *newp;
+ newp = (char *) __alloca (end_name - dirname);
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ = '\0';
+ user_name = newp;
+ }
+
+ /* Look up specific user's home directory. */
+ {
+ struct passwd *p;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int buflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+# ifndef _LIBC
+ if (buflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
+ moderate value. */
+ buflen = 1024;
+# endif
+ pwtmpbuf = (char *) __alloca (buflen);
+
+ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+# ifdef _LIBC
+ pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+# else
+ buflen *= 2;
+ pwtmpbuf = __alloca (buflen);
+# endif
+ __set_errno (save);
+ }
+# else
+ p = getpwnam (user_name);
+# endif
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ else
+ home_dir = NULL;
+ }
+ /* If we found a home directory use this. */
+ if (home_dir != NULL)
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+ newp = (char *) __alloca (home_len + rest_len + 1);
+ *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+ end_name, rest_len)) = '\0';
+ dirname = newp;
+ }
+ else
+ if (flags & GLOB_TILDE_CHECK)
+ /* We have to regard it as an error if we cannot find the
+ home directory. */
+ return GLOB_NOMATCH;
+ }
+# endif /* Not Amiga && not WINDOWS32. */
+ }
+#endif /* Not VMS. */
+
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+ struct stat st;
+ struct_stat64 st64;
+
+ /* Return the directory if we don't check for error or if it exists. */
+ if ((flags & GLOB_NOCHECK)
+ || (((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_stat) (dirname, &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (newcount + 1 + 1) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ nospace:
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ pglob->gl_pathv[++newcount] = NULL;
+ ++pglob->gl_pathc;
+ pglob->gl_flags = flags;
+
+ return 0;
+ }
+
+ /* Not found. */
+ return GLOB_NOMATCH;
+ }
+
+ if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+ {
+ /* The directory name contains metacharacters, so we
+ have to glob for the directory, and then glob for
+ the pattern in each directory found. */
+ glob_t dirs;
+ size_t i;
+
+ if ((flags & GLOB_ALTDIRFUNC) != 0)
+ {
+ /* Use the alternative access functions also in the recursive
+ call. */
+ dirs.gl_opendir = pglob->gl_opendir;
+ dirs.gl_readdir = pglob->gl_readdir;
+ dirs.gl_closedir = pglob->gl_closedir;
+ dirs.gl_stat = pglob->gl_stat;
+ dirs.gl_lstat = pglob->gl_lstat;
+ }
+
+ status = glob (dirname,
+ ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
+ | GLOB_ALTDIRFUNC))
+ | GLOB_NOSORT | GLOB_ONLYDIR),
+ errfunc, &dirs);
+ if (status != 0)
+ return status;
+
+ /* We have successfully globbed the preceding directory name.
+ For each name we found, call glob_in_dir on it and FILENAME,
+ appending the results to PGLOB. */
+ for (i = 0; i < dirs.gl_pathc; ++i)
+ {
+ int old_pathc;
+
+#ifdef SHELL
+ {
+ /* Make globbing interruptible in the bash shell. */
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ {
+ globfree (&dirs);
+ return GLOB_ABORTED;
+ }
+ }
+#endif /* SHELL. */
+
+ old_pathc = pglob->gl_pathc;
+ status = glob_in_dir (filename, dirs.gl_pathv[i],
+ ((flags | GLOB_APPEND)
+ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+ errfunc, pglob);
+ if (status == GLOB_NOMATCH)
+ /* No matches in this directory. Try the next. */
+ continue;
+
+ if (status != 0)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return status;
+ }
+
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirs.gl_pathv[i],
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+
+ flags |= GLOB_MAGCHAR;
+
+ /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+ But if we have not found any matching entry and the GLOB_NOCHECK
+ flag was set we must return the input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+ {
+ /* No matches. */
+ if (flags & GLOB_NOCHECK)
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv = (char **) realloc (pglob->gl_pathv,
+ (newcount + 2)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ globfree (&dirs);
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = __strdup (pattern);
+ if (pglob->gl_pathv[newcount] == NULL)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ ++pglob->gl_pathc;
+ ++newcount;
+
+ pglob->gl_pathv[newcount] = NULL;
+ pglob->gl_flags = flags;
+ }
+ else
+ {
+ globfree (&dirs);
+ return GLOB_NOMATCH;
+ }
+ }
+
+ globfree (&dirs);
+ }
+ else
+ {
+ int old_pathc = pglob->gl_pathc;
+
+ status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
+ if (status != 0)
+ return status;
+
+ if (dirlen > 0)
+ {
+ /* Stick the directory on the front of each name. */
+ if (prefix_array (dirname,
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+ }
+
+ if (flags & GLOB_MARK)
+ {
+ /* Append slashes to directory names. */
+ size_t i;
+ struct stat st;
+ struct_stat64 st64;
+
+ for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
+ if (((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (pglob->gl_pathv[i], &st64) == 0
+ && S_ISDIR (st64.st_mode))))
+ {
+ size_t len = strlen (pglob->gl_pathv[i]) + 2;
+ char *new = realloc (pglob->gl_pathv[i], len);
+ if (new == NULL)
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ strcpy (&new[len - 2], "/");
+ pglob->gl_pathv[i] = new;
+ }
+ }
+
+ if (!(flags & GLOB_NOSORT))
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+ pglob->gl_pathc + pglob->gl_offs - oldcount,
+ sizeof (char *), collated_compare);
+ }
+
+ return 0;
+}
+#if defined _LIBC && !defined glob
+libc_hidden_def (glob)
+#endif
+
+
+#if !defined _LIBC || !defined GLOB_ONLY_P
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+void
+globfree (pglob)
+ register glob_t *pglob;
+{
+ if (pglob->gl_pathv != NULL)
+ {
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+#if defined _LIBC && !defined globfree
+libc_hidden_def (globfree)
+#endif
+
+
+/* Do a collated comparison of A and B. */
+static int
+collated_compare (const void *a, const void *b)
+{
+ const char *const s1 = *(const char *const * const) a;
+ const char *const s2 = *(const char *const * const) b;
+
+ if (s1 == s2)
+ return 0;
+ if (s1 == NULL)
+ return 1;
+ if (s2 == NULL)
+ return -1;
+ return strcoll (s1, s2);
+}
+
+
+/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
+ elements in place. Return nonzero if out of memory, zero if successful.
+ A slash is inserted between DIRNAME and each elt of ARRAY,
+ unless DIRNAME is just "/". Each old element of ARRAY is freed. */
+static int
+prefix_array (const char *dirname, char **array, size_t n)
+{
+ register size_t i;
+ size_t dirlen = strlen (dirname);
+#if defined __MSDOS__ || defined WINDOWS32
+ int sep_char = '/';
+# define DIRSEP_CHAR sep_char
+#else
+# define DIRSEP_CHAR '/'
+#endif
+
+ if (dirlen == 1 && dirname[0] == '/')
+ /* DIRNAME is just "/", so normal prepending would get us "//foo".
+ We want "/foo" instead, so don't prepend any chars from DIRNAME. */
+ dirlen = 0;
+#if defined __MSDOS__ || defined WINDOWS32
+ else if (dirlen > 1)
+ {
+ if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
+ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
+ --dirlen;
+ else if (dirname[dirlen - 1] == ':')
+ {
+ /* DIRNAME is "d:". Use `:' instead of `/'. */
+ --dirlen;
+ sep_char = ':';
+ }
+ }
+#endif
+
+ for (i = 0; i < n; ++i)
+ {
+ size_t eltlen = strlen (array[i]) + 1;
+ char *new = (char *) malloc (dirlen + 1 + eltlen);
+ if (new == NULL)
+ {
+ while (i > 0)
+ free (array[--i]);
+ return 1;
+ }
+
+ {
+ char *endp = mempcpy (new, dirname, dirlen);
+ *endp++ = DIRSEP_CHAR;
+ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
+ array[i] = new;
+ }
+
+ return 0;
+}
+
+
+/* We must not compile this function twice. */
+#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+int
+__glob_pattern_p (pattern, quote)
+ const char *pattern;
+ int quote;
+{
+ register const char *p;
+ int open = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '\\':
+ if (quote && p[1] != '\0')
+ ++p;
+ break;
+
+ case '[':
+ open = 1;
+ break;
+
+ case ']':
+ if (open)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+# ifdef _LIBC
+weak_alias (__glob_pattern_p, glob_pattern_p)
+# endif
+#endif
+
+#endif /* !GLOB_ONLY_P */
+
+
+/* We put this in a separate function mainly to allow the memory
+ allocated with alloca to be recycled. */
+#if !defined _LIBC || !defined GLOB_ONLY_P
+static int
+link_exists_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+ size_t fnamelen = strlen (fname);
+ char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
+ struct stat st;
+ struct_stat64 st64;
+
+ mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+ fname, fnamelen + 1);
+
+ return (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0);
+}
+#endif
+
+
+/* Like `glob', but PATTERN is a final pathname component,
+ and matches are searched for in DIRECTORY.
+ The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
+ The GLOB_APPEND flag is assumed to be set (always appends). */
+static int
+glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob)
+{
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
+ struct globlink
+ {
+ struct globlink *next;
+ char *name;
+ };
+ struct globlink *names = NULL;
+ size_t nfound;
+ int meta;
+ int save;
+
+ meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+ /* We need not do any tests. The PATTERN contains no meta
+ characters and we must not return an error therefore the
+ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+ nfound = 0;
+ }
+ else if (meta == 0 &&
+ ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL))
+ {
+ /* Since we use the normal file functions we can also use stat()
+ to verify the file is there. */
+ struct stat st;
+ struct_stat64 st64;
+ size_t patlen = strlen (pattern);
+ char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);
+
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+ "/", 1),
+ pattern, patlen + 1);
+ if (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0)
+ /* We found this file to be existing. Now tell the rest
+ of the function to copy this name into the result. */
+ flags |= GLOB_NOCHECK;
+
+ nfound = 0;
+ }
+ else
+ {
+ if (pattern[0] == '\0')
+ {
+ /* This is a special case for matching directories like in
+ "*a/". */
+ names = (struct globlink *) __alloca (sizeof (struct globlink));
+ names->name = (char *) malloc (1);
+ if (names->name == NULL)
+ goto memory_error;
+ names->name[0] = '\0';
+ names->next = NULL;
+ nfound = 1;
+ meta = 0;
+ }
+ else
+ {
+ stream = ((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_opendir) (directory)
+ : opendir (directory));
+ if (stream == NULL)
+ {
+ if (errno != ENOTDIR
+ && ((errfunc != NULL && (*errfunc) (directory, errno))
+ || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+ nfound = 0;
+ meta = 0;
+ }
+ else
+ {
+ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+#if defined _AMIGA || defined VMS
+ | FNM_CASEFOLD
+#endif
+ );
+ nfound = 0;
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+ {
+ const char *name;
+ size_t len;
+#if defined _LIBC && !defined COMPILE_GLOB64
+ struct dirent64 *d;
+ union
+ {
+ struct dirent64 d64;
+ char room [offsetof (struct dirent64, d_name[0])
+ + NAME_MAX + 1];
+ }
+ d64buf;
+
+ if (flags & GLOB_ALTDIRFUNC)
+ {
+ struct dirent *d32 = (*pglob->gl_readdir) (stream);
+ if (d32 != NULL)
+ {
+ CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+ d = &d64buf.d64;
+ }
+ else
+ d = NULL;
+ }
+ else
+ d = __readdir64 (stream);
+#else
+ struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
+ ? ((struct dirent *)
+ (*pglob->gl_readdir) (stream))
+ : __readdir (stream));
+#endif
+ if (d == NULL)
+ break;
+ if (! REAL_DIR_ENTRY (d))
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+ if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+ continue;
+
+ name = d->d_name;
+
+ if (fnmatch (pattern, name, fnm_flags) == 0)
+ {
+ /* If the file we found is a symlink we have to
+ make sure the target file exists. */
+ if (!DIRENT_MIGHT_BE_SYMLINK (d)
+ || link_exists_p (directory, dirlen, name, pglob,
+ flags))
+ {
+ struct globlink *new = (struct globlink *)
+ __alloca (sizeof (struct globlink));
+ len = NAMLEN (d);
+ new->name = (char *) malloc (len + 1);
+ if (new->name == NULL)
+ goto memory_error;
+ *((char *) mempcpy (new->name, name, len)) = '\0';
+ new->next = names;
+ names = new;
+ ++nfound;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (nfound == 0 && (flags & GLOB_NOCHECK))
+ {
+ size_t len = strlen (pattern);
+ nfound = 1;
+ names = (struct globlink *) __alloca (sizeof (struct globlink));
+ names->next = NULL;
+ names->name = (char *) malloc (len + 1);
+ if (names->name == NULL)
+ goto memory_error;
+ *((char *) mempcpy (names->name, pattern, len)) = '\0';
+ }
+
+ if (nfound != 0)
+ {
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto memory_error;
+ pglob->gl_pathv = new_gl_pathv;
+
+ for (; names != NULL; names = names->next)
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ pglob->gl_flags = flags;
+ }
+
+ save = errno;
+ if (stream != NULL)
+ {
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ }
+ __set_errno (save);
+
+ return nfound == 0 ? GLOB_NOMATCH : 0;
+
+ memory_error:
+ {
+ int save = errno;
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ __set_errno (save);
+ }
+ while (names != NULL)
+ {
+ if (names->name != NULL)
+ free (names->name);
+ names = names->next;
+ }
+ return GLOB_NOSPACE;
+}
diff --git a/libc/posix/glob.h b/libc/posix/glob.h
new file mode 100644
index 000000000..3d401f082
--- /dev/null
+++ b/libc/posix/glob.h
@@ -0,0 +1,194 @@
+/* Copyright (C) 1991,92,95-98,2000,2001,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _GLOB_H
+#define _GLOB_H 1
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* We need `size_t' for the following definitions. */
+#ifndef __size_t
+# if defined __GNUC__ && __GNUC__ >= 2
+typedef __SIZE_TYPE__ __size_t;
+# ifdef __USE_XOPEN
+typedef __SIZE_TYPE__ size_t;
+# endif
+# else
+# include <stddef.h>
+# ifndef __size_t
+# define __size_t size_t
+# endif
+# endif
+#else
+/* The GNU CC stddef.h version defines __size_t as empty. We need a real
+ definition. */
+# undef __size_t
+# define __size_t size_t
+#endif
+
+/* Bits set in the FLAGS argument to `glob'. */
+#define GLOB_ERR (1 << 0)/* Return on read errors. */
+#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
+#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
+#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
+#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
+#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
+#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
+#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
+
+#if !defined __USE_POSIX2 || defined __USE_BSD || defined __USE_GNU
+# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
+# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
+# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
+# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
+# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
+# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
+# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
+ if the user name is not available. */
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
+ GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
+#else
+# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+ GLOB_PERIOD)
+#endif
+
+/* Error returns from `glob'. */
+#define GLOB_NOSPACE 1 /* Ran out of memory. */
+#define GLOB_ABORTED 2 /* Read error. */
+#define GLOB_NOMATCH 3 /* No matches found. */
+#define GLOB_NOSYS 4 /* Not implemented. */
+#ifdef __USE_GNU
+/* Previous versions of this file defined GLOB_ABEND instead of
+ GLOB_ABORTED. Provide a compatibility definition here. */
+# define GLOB_ABEND GLOB_ABORTED
+#endif
+
+/* Structure describing a globbing run. */
+#ifdef __USE_GNU
+struct stat;
+#endif
+typedef struct
+ {
+ __size_t gl_pathc; /* Count of paths matched by the pattern. */
+ char **gl_pathv; /* List of matched pathnames. */
+ __size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
+ int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+#ifdef __USE_GNU
+ struct dirent *(*gl_readdir) (void *);
+#else
+ void *(*gl_readdir) (void *);
+#endif
+ void *(*gl_opendir) (__const char *);
+#ifdef __USE_GNU
+ int (*gl_lstat) (__const char *__restrict, struct stat *__restrict);
+ int (*gl_stat) (__const char *__restrict, struct stat *__restrict);
+#else
+ int (*gl_lstat) (__const char *__restrict, void *__restrict);
+ int (*gl_stat) (__const char *__restrict, void *__restrict);
+#endif
+ } glob_t;
+
+#ifdef __USE_LARGEFILE64
+# ifdef __USE_GNU
+struct stat64;
+# endif
+typedef struct
+ {
+ __size_t gl_pathc;
+ char **gl_pathv;
+ __size_t gl_offs;
+ int gl_flags;
+
+ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+ are used instead of the normal file access functions. */
+ void (*gl_closedir) (void *);
+# ifdef __USE_GNU
+ struct dirent64 *(*gl_readdir) (void *);
+# else
+ void *(*gl_readdir) (void *);
+# endif
+ void *(*gl_opendir) (__const char *);
+# ifdef __USE_GNU
+ int (*gl_lstat) (__const char *__restrict, struct stat64 *__restrict);
+ int (*gl_stat) (__const char *__restrict, struct stat64 *__restrict);
+# else
+ int (*gl_lstat) (__const char *__restrict, void *__restrict);
+ int (*gl_stat) (__const char *__restrict, void *__restrict);
+# endif
+ } glob64_t;
+#endif
+
+#if __USE_FILE_OFFSET64 && __GNUC__ < 2
+# define glob glob64
+# define globfree globfree64
+#endif
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+#if !defined __USE_FILE_OFFSET64 || __GNUC__ < 2
+extern int glob (__const char *__restrict __pattern, int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob_t *__restrict __pglob) __THROW;
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+extern void globfree (glob_t *__pglob) __THROW;
+#else
+extern int __REDIRECT_NTH (glob, (__const char *__restrict __pattern,
+ int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob_t *__restrict __pglob), glob64);
+
+extern void __REDIRECT_NTH (globfree, (glob_t *__pglob), globfree64);
+#endif
+
+#ifdef __USE_LARGEFILE64
+extern int glob64 (__const char *__restrict __pattern, int __flags,
+ int (*__errfunc) (__const char *, int),
+ glob64_t *__restrict __pglob) __THROW;
+
+extern void globfree64 (glob64_t *__pglob) __THROW;
+#endif
+
+
+#ifdef __USE_GNU
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero.
+
+ This function is not part of the interface specified by POSIX.2
+ but several programs want to use it. */
+extern int glob_pattern_p (__const char *__pattern, int __quote) __THROW;
+#endif
+
+__END_DECLS
+
+#endif /* glob.h */
diff --git a/libc/posix/glob/ChangeLog b/libc/posix/glob/ChangeLog
new file mode 100644
index 000000000..de04c4b94
--- /dev/null
+++ b/libc/posix/glob/ChangeLog
@@ -0,0 +1,23 @@
+Sat Jul 20 21:55:31 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ Win32 hacks from <Rob_Tulloh@tivoli.com>.
+ * posix/glob.c [WIN32]: Don't include <pwd.h>; don't use d_ino;
+ use void * for my_realloc; include <malloc.h> for alloca.
+ (glob) [WIN32]: Use "c:/users/default" for ~ if no HOME variable.
+ * posix/fnmatch.h [WIN32]: Use prototypes even if [!__STDC__].
+ * posix/glob.h: Likewise.
+
+Fri Jul 19 16:56:41 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * posix/glob.h [!_AMIGA && !VMS]: Check this instead of just [!_AMIGA]
+ for `struct stat;' forward decl.
+
+Sat Jun 22 10:44:09 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * posix/glob.c: Include <alloca.h> only [HAVE_ALLOCA_H], not [sparc].
+
+Fri Jun 21 00:27:51 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * posix/fnmatch.c (fnmatch): Fix \*[*?]+ case to increment name ptr
+ only for ?s, not for *s. Fix from Chet Ramey.
+
diff --git a/libc/posix/glob/Makefile.ami b/libc/posix/glob/Makefile.ami
new file mode 100644
index 000000000..25916226c
--- /dev/null
+++ b/libc/posix/glob/Makefile.ami
@@ -0,0 +1,69 @@
+# Makefile for standalone distribution of libglob.a (fnmatch, glob).
+
+# Copyright (C) 1991, 92, 93, 94, 95, 97 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; see the file COPYING.LIB. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# Ultrix 2.2 make doesn't expand the value of VPATH.
+VPATH = /glob/
+# This must repeat the value, because configure will remove `VPATH = .'.
+srcdir = /glob/
+
+CC = sc
+RM = delete
+CPPFLAGS =
+CFLAGS =
+
+# Information determined by configure.
+DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \
+ Define HAVE_DIRENT_H
+
+# How to invoke ar.
+AR = join
+ARFLAGS = as
+
+# How to invoke ranlib.
+RANLIB = ;
+
+.PHONY: all
+all: glob.lib
+
+glob.lib : glob.o fnmatch.o
+ $(AR) $(ARFLAGS) $@ glob.o fnmatch.o
+ $(RANLIB) $@
+
+# For some reason, Unix make wants the dependencies on the source files.
+# Otherwise it refuses to use an implicit rule!
+# And, get this: it doesn't work to use $(srcdir)foo.c!!
+glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c
+fnmatch.o: $(srcdir)fnmatch.h fnmatch.c
+
+OUTPUT_OPTION =
+.c.o:
+ $(CC) IDir "" \
+ $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION)
+
+.PHONY: clean realclean glob-clean glob-realclean distclean
+clean glob-clean:
+ -$(RM) glob.lib "#?.o" core
+distclean glob-realclean: clean
+ -$(RM) TAGS tags Makefile config.status config.h config.log
+realcean: distclean
+
+# For inside the C library.
+glob.tar glob.tar.Z:
+ $(MAKE) -C .. $@
diff --git a/libc/posix/glob/Makefile.in b/libc/posix/glob/Makefile.in
new file mode 100644
index 000000000..dde4edbe6
--- /dev/null
+++ b/libc/posix/glob/Makefile.in
@@ -0,0 +1,66 @@
+# Makefile for standalone distribution of libglob.a (fnmatch, glob).
+
+# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; see the file COPYING.LIB. If
+# not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111 USA.
+
+# Ultrix 2.2 make doesn't expand the value of VPATH.
+VPATH = @srcdir@
+# This must repeat the value, because configure will remove `VPATH = .'.
+srcdir = @srcdir@
+
+CC = @CC@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+
+# Information determined by configure.
+DEFS = @DEFS@
+
+# How to invoke ar.
+AR = @AR@
+ARFLAGS = rv
+
+# How to invoke ranlib.
+RANLIB = @RANLIB@
+
+.PHONY: all
+all: libglob.a
+
+libglob.a: glob.o fnmatch.o
+ $(AR) $(ARFLAGS) $@ glob.o fnmatch.o
+ $(RANLIB) $@
+
+# For some reason, Unix make wants the dependencies on the source files.
+# Otherwise it refuses to use an implicit rule!
+# And, get this: it doesn't work to use $(srcdir)/foo.c!!
+glob.o: $(srcdir)/glob.h $(srcdir)/fnmatch.h glob.c
+fnmatch.o: $(srcdir)/fnmatch.h fnmatch.c
+
+.c.o:
+ $(CC) -I. -I$(srcdir) -c \
+ $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION)
+
+.PHONY: clean realclean glob-clean glob-realclean distclean
+clean glob-clean:
+ -rm -f libglob.a *.o core
+distclean glob-realclean: clean
+ -rm -f TAGS tags Makefile config.status config.h config.log
+realcean: distclean
+
+# For inside the C library.
+glob.tar glob.tar.Z:
+ $(MAKE) -C .. $@
diff --git a/libc/posix/glob/SCOPTIONS b/libc/posix/glob/SCOPTIONS
new file mode 100644
index 000000000..f89daae12
--- /dev/null
+++ b/libc/posix/glob/SCOPTIONS
@@ -0,0 +1,13 @@
+ERRORREXX
+OPTIMIZE
+NOVERSION
+OPTIMIZERTIME
+OPTIMIZERALIAS
+DEFINE INCLUDEDIR="include:"
+DEFINE LIBDIR="lib:"
+DEFINE NO_ALLOCA
+DEFINE NO_FLOAT
+DEFINE NO_ARCHIVES
+IGNORE=161
+IGNORE=100
+STARTUP=cres
diff --git a/libc/posix/glob/SMakefile b/libc/posix/glob/SMakefile
new file mode 100644
index 000000000..6e284db1f
--- /dev/null
+++ b/libc/posix/glob/SMakefile
@@ -0,0 +1,68 @@
+# Makefile for standalone distribution of libglob.a (fnmatch, glob).
+# Copyright (C) 1991, 92, 93, 94, 95, 97 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+# Ultrix 2.2 make doesn't expand the value of VPATH.
+VPATH = /glob/
+# This must repeat the value, because configure will remove `VPATH = .'.
+srcdir = /glob/
+
+CC = sc
+CPPFLAGS =
+CFLAGS =
+MAKE = smake
+RM = delete
+
+# Information determined by configure.
+DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \
+ Define HAVE_DIRENT_H
+
+# How to invoke ar.
+AR = join
+ARFLAGS = as
+
+# How to invoke ranlib.
+RANLIB = ;
+
+.PHONY: all
+all: glob.lib
+
+glob.lib : glob.o fnmatch.o
+ $(AR) $(ARFLAGS) $@ glob.o fnmatch.o
+ $(RANLIB) $@
+
+# For some reason, Unix make wants the dependencies on the source files.
+# Otherwise it refuses to use an implicit rule!
+# And, get this: it doesn't work to use $(srcdir)foo.c!!
+glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c
+fnmatch.o: $(srcdir)fnmatch.h fnmatch.c
+
+.c.o:
+ $(CC) IDir "" \
+ $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION)
+
+.PHONY: clean realclean glob-clean glob-realclean distclean
+clean glob-clean:
+ -$(RM) -f glob.lib *.o core
+distclean glob-realclean: clean
+ -$(RM) -f TAGS tags Makefile config.status config.h config.log
+realcean: distclean
+
+# For inside the C library.
+glob.tar glob.tar.Z:
+ $(MAKE) -C .. $@
diff --git a/libc/posix/glob/configure b/libc/posix/glob/configure
new file mode 100755
index 000000000..157294527
--- /dev/null
+++ b/libc/posix/glob/configure
@@ -0,0 +1,1664 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.7
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.7"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=fnmatch.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ ac_prog_rejected=no
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:601: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="ar"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 709 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:715: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 724 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:730: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+ echo $ac_n "checking for AIX""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 751 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+ yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+ac_safe=`echo "minix/config.h" | tr './\055' '___'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 778 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:783: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ MINIX=yes
+else
+ echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+if test -d /etc/conf/kconfig.d &&
+ grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+ echo "$ac_t""yes" 1>&6
+ ISC=yes # If later tests want to check for ISC.
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+else
+ echo "$ac_t""no" 1>&6
+ ISC=
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 843 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:893: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 921 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+{ (eval echo configure:925: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_cross=no
+else
+ ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_cross" 1>&6
+cross_compiling=$ac_cv_c_cross
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 943 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:951: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 966 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 984 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+cat > conftest.$ac_ext <<EOF
+#line 1005 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+{ (eval echo configure:1016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in memory.h unistd.h string.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1043 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1048: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1081 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() { return 0; }
+int t() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1090: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdedfghijklmnopqrstuvwxyz./\055' 'ABCDEDFGHIJKLMNOPQRSTUVWXYZ___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for -ldir""... $ac_c" 1>&6
+ac_lib_var=`echo dir | tr '.-/+' '___p'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1121 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for -lx""... $ac_c" 1>&6
+ac_lib_var=`echo x | tr '.-/+' '___p'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1156 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1164: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_closedir_void'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_closedir_void=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 1192 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_header_dirent>
+int closedir(); main() { exit(closedir(opendir(".")) != 0); }
+EOF
+{ (eval echo configure:1198: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_func_closedir_void=no
+else
+ ac_cv_func_closedir_void=yes
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_closedir_void" 1>&6
+if test $ac_cv_func_closedir_void = yes; then
+ cat >> confdefs.h <<\EOF
+#define CLOSEDIR_VOID 1
+EOF
+
+fi
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1223 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() { return 0; }
+int t() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:1231: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_alloca_h=yes
+else
+ rm -rf conftest*
+ ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_alloca'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1255 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:1279: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_func_alloca=yes
+else
+ rm -rf conftest*
+ ac_cv_func_alloca=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_func_alloca" 1>&6
+if test $ac_cv_func_alloca = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.o
+ cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1314 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "webecray" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_os_cray=yes
+else
+ rm -rf conftest*
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+ echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1343 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+char $ac_func();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+cat > conftest.$ac_ext <<EOF
+#line 1397 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+ exit (find_stack_direction() < 0);
+}
+EOF
+{ (eval echo configure:1416: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_stack_direction=1
+else
+ ac_cv_c_stack_direction=-1
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+echo $ac_n "checking for strcoll""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_strcoll'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_strcoll=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 1441 "configure"
+#include "confdefs.h"
+#include <string.h>
+main ()
+{
+ exit (strcoll ("abc", "def") >= 0 ||
+ strcoll ("ABC", "DEF") >= 0 ||
+ strcoll ("123", "456") >= 0);
+}
+EOF
+{ (eval echo configure:1451: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_func_strcoll=yes
+else
+ ac_cv_func_strcoll=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_strcoll" 1>&6
+if test $ac_cv_func_strcoll = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRCOLL 1
+EOF
+
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
+ >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.7"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@AR@%$AR%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@ALLOCA@%$ALLOCA%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/libc/posix/glob/configure.bat b/libc/posix/glob/configure.bat
new file mode 100644
index 000000000..f3a0f5db6
--- /dev/null
+++ b/libc/posix/glob/configure.bat
@@ -0,0 +1,26 @@
+@echo off
+echo Configuring glob for GO32
+rem This batch file assumes a unix-type "sed" program
+
+echo # Makefile generated by "configure.bat"> Makefile
+
+if exist config.sed del config.sed
+
+echo "s/@srcdir@/./ ">> config.sed
+echo "s/@CC@/gcc/ ">> config.sed
+echo "s/@CFLAGS@/-O2 -g/ ">> config.sed
+echo "s/@CPPFLAGS@/-DHAVE_CONFIG_H -I../ ">> config.sed
+echo "s/@AR@/ar/ ">> config.sed
+echo "s/@RANLIB@/ranlib/ ">> config.sed
+echo "s/@LDFLAGS@// ">> config.sed
+echo "s/@DEFS@// ">> config.sed
+echo "s/@ALLOCA@// ">> config.sed
+echo "s/@LIBS@// ">> config.sed
+echo "s/@LIBOBJS@// ">> config.sed
+echo "s/^Makefile *:/_Makefile:/ ">> config.sed
+echo "s/^config.h *:/_config.h:/ ">> config.sed
+
+sed -e "s/^\"//" -e "s/\"$//" -e "s/[ ]*$//" config.sed > config2.sed
+sed -f config2.sed Makefile.in >> Makefile
+del config.sed
+del config2.sed
diff --git a/libc/posix/glob/configure.in b/libc/posix/glob/configure.in
new file mode 100644
index 000000000..8dc68e424
--- /dev/null
+++ b/libc/posix/glob/configure.in
@@ -0,0 +1,19 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(fnmatch.c) dnl A distinctive file to look for in srcdir.
+AC_PREREQ(2.1) dnl Minimum Autoconf version required.
+AC_PROG_CC
+AC_CHECK_PROG(AR, ar, ar, ar)
+AC_PROG_RANLIB
+AC_PROG_CPP dnl Later checks need this.
+dnl These two want to come early.
+AC_AIX
+AC_MINIX
+AC_ISC_POSIX
+AC_CONST
+AC_HEADER_STDC
+AC_CHECK_HEADERS(memory.h unistd.h string.h)
+AC_HEADER_DIRENT
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_ALLOCA
+AC_FUNC_STRCOLL
+AC_OUTPUT(Makefile)
diff --git a/libc/posix/glob64.c b/libc/posix/glob64.c
new file mode 100644
index 000000000..2bfab7407
--- /dev/null
+++ b/libc/posix/glob64.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1998,99,2002,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <glob.h>
+#include <errno.h>
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+int
+glob64 (const char *pattern, int flags,
+ int (*errfunc) (const char *, int), glob64_t *pglob)
+{
+ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return GLOB_NOSYS;
+}
+libc_hidden_def (glob64)
+
+void
+globfree64 (glob64_t *pglob)
+{
+}
+libc_hidden_def (globfree64)
+
+stub_warning (glob64)
+#include <stub-tag.h>
diff --git a/libc/posix/globtest.c b/libc/posix/globtest.c
new file mode 100644
index 000000000..5f1ffb74f
--- /dev/null
+++ b/libc/posix/globtest.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glob.h>
+
+int
+main (int argc, char *argv[])
+{
+ int i, j;
+ int glob_flags = 0;
+ glob_t g;
+ int quotes = 1;
+
+ g.gl_offs = 0;
+
+ while ((i = getopt (argc, argv, "bcdeEgmopqstT")) != -1)
+ switch(i)
+ {
+ case 'b':
+ glob_flags |= GLOB_BRACE;
+ break;
+ case 'c':
+ glob_flags |= GLOB_NOCHECK;
+ break;
+ case 'd':
+ glob_flags |= GLOB_ONLYDIR;
+ break;
+ case 'e':
+ glob_flags |= GLOB_NOESCAPE;
+ break;
+ case 'E':
+ glob_flags |= GLOB_ERR;
+ break;
+ case 'g':
+ glob_flags |= GLOB_NOMAGIC;
+ break;
+ case 'm':
+ glob_flags |= GLOB_MARK;
+ break;
+ case 'o':
+ glob_flags |= GLOB_DOOFFS;
+ g.gl_offs = 1;
+ break;
+ case 'p':
+ glob_flags |= GLOB_PERIOD;
+ break;
+ case 'q':
+ quotes = 0;
+ break;
+ case 's':
+ glob_flags |= GLOB_NOSORT;
+ break;
+ case 't':
+ glob_flags |= GLOB_TILDE;
+ break;
+ case 'T':
+ glob_flags |= GLOB_TILDE_CHECK;
+ break;
+ default:
+ exit (-1);
+ }
+
+ if (optind >= argc || chdir (argv[optind]))
+ exit(1);
+
+ j = optind + 1;
+ if (optind + 1 >= argc)
+ exit (1);
+
+ /* Do a glob on each remaining argument. */
+ for (j = optind + 1; j < argc; j++) {
+ i = glob (argv[j], glob_flags, NULL, &g);
+ if (i != 0)
+ break;
+ glob_flags |= GLOB_APPEND;
+ }
+
+ /* Was there an error? */
+ if (i == GLOB_NOSPACE)
+ puts ("GLOB_NOSPACE");
+ else if (i == GLOB_ABORTED)
+ puts ("GLOB_ABORTED");
+ else if (i == GLOB_NOMATCH)
+ puts ("GLOB_NOMATCH");
+
+ /* If we set an offset, fill in the first field.
+ (Unless glob() has filled it in already - which is an error) */
+ if ((glob_flags & GLOB_DOOFFS) && g.gl_pathv[0] == NULL)
+ g.gl_pathv[0] = (char *) "abc";
+
+ /* Print out the names. Unless otherwise specified, qoute them. */
+ if (g.gl_pathv)
+ {
+ for (i = 0; i < g.gl_offs + g.gl_pathc; ++i)
+ printf ("%s%s%s\n", quotes ? "`" : "",
+ g.gl_pathv[i] ? g.gl_pathv[i] : "(null)",
+ quotes ? "'" : "");
+ }
+ return 0;
+}
diff --git a/libc/posix/globtest.sh b/libc/posix/globtest.sh
new file mode 100755
index 000000000..09af6f74f
--- /dev/null
+++ b/libc/posix/globtest.sh
@@ -0,0 +1,724 @@
+#! /bin/sh
+
+common_objpfx=$1; shift
+elf_objpfx=$1; shift
+rtld_installed_name=$1; shift
+logfile=$common_objpfx/posix/globtest.out
+
+#CMP=cmp
+CMP="diff -u"
+
+# We have to make the paths `common_objpfx' absolute.
+case "$common_objpfx" in
+ .*)
+ common_objpfx="`pwd`/$common_objpfx"
+ ;;
+ *)
+ ;;
+esac
+
+# We have to find the libc and the NSS modules.
+library_path=${common_objpfx}:${common_objpfx}nss:${common_objpfx}nis:${common_objpfx}db2:${common_objpfx}hesiod
+
+# Since we use `sort' we must make sure to use the same locale everywhere.
+LC_ALL=C
+export LC_ALL
+LANG=C
+export LANG
+
+# Create the arena
+: ${TMPDIR=/tmp}
+testdir=$TMPDIR/globtest-dir
+testout=$TMPDIR/globtest-out
+
+trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15
+
+test -d $testdir/noread && chmod 777 $testdir/noread
+rm -fr $testdir 2>/dev/null
+mkdir $testdir
+echo 1 > $testdir/file1
+echo 2 > $testdir/file2
+echo 3 > $testdir/-file3
+echo 4 > $testdir/~file4
+echo 5 > $testdir/.file5
+echo 6 > $testdir/'*file6'
+echo 7 > $testdir/'{file7,}'
+echo 8 > $testdir/'\{file8\}'
+echo 9 > $testdir/'\{file9\,file9b\}'
+echo 9 > $testdir/'\file9b\' #'
+echo a > $testdir/'filea,'
+echo a > $testdir/'fileb}c'
+mkdir $testdir/dir1
+mkdir $testdir/dir2
+test -d $testdir/noread || mkdir $testdir/noread
+chmod a-r $testdir/noread
+echo 1_1 > $testdir/dir1/file1_1
+echo 1_2 > $testdir/dir1/file1_2
+ln -fs dir1 $testdir/link1
+
+# Run some tests.
+result=0
+rm -f $logfile
+
+# Normal test
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+`-file3'
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+`dir1'
+`dir2'
+`file1'
+`file2'
+`filea,'
+`fileb}c'
+`link1'
+`noread'
+`{file7,}'
+`~file4'
+EOF
+if test $failed -ne 0; then
+ echo "Normal test failed" >> $logfile
+ result=1
+fi
+
+# Don't let glob sort it
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -s "$testdir" "*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+`-file3'
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+`dir1'
+`dir2'
+`file1'
+`file2'
+`filea,'
+`fileb}c'
+`link1'
+`noread'
+`{file7,}'
+`~file4'
+EOF
+if test $failed -ne 0; then
+ echo "No sort test failed" >> $logfile
+ result=1
+fi
+
+# Mark directories
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -m "$testdir" "*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+`-file3'
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+`dir1/'
+`dir2/'
+`file1'
+`file2'
+`filea,'
+`fileb}c'
+`link1/'
+`noread/'
+`{file7,}'
+`~file4'
+EOF
+if test $failed -ne 0; then
+ echo "Mark directories test failed" >> $logfile
+ result=1
+fi
+
+# Find files starting with .
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -p "$testdir" "*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+`-file3'
+`.'
+`..'
+`.file5'
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+`dir1'
+`dir2'
+`file1'
+`file2'
+`filea,'
+`fileb}c'
+`link1'
+`noread'
+`{file7,}'
+`~file4'
+EOF
+if test $failed -ne 0; then
+ echo "Leading period test failed" >> $logfile
+ result=1
+fi
+
+# Test braces
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" "file{1,2}" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`file1'
+`file2'
+EOF
+if test $failed -ne 0; then
+ echo "Braces test failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" "{file{1,2},-file3}" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`-file3'
+`file1'
+`file2'
+EOF
+if test $failed -ne 0; then
+ echo "Braces test 2 failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" "{" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Braces test 3 failed" >> $logfile
+ result=1
+fi
+
+# Test NOCHECK
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -c "$testdir" "abc" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`abc'
+EOF
+if test $failed -ne 0; then
+ echo "No check test failed" >> $logfile
+ result=1
+fi
+
+# Test NOMAGIC without magic characters
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -g "$testdir" "abc" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`abc'
+EOF
+if test $failed -ne 0; then
+ echo "No magic test failed" >> $logfile
+ result=1
+fi
+
+# Test NOMAGIC with magic characters
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -g "$testdir" "abc*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "No magic w/ magic chars test failed" >> $logfile
+ result=1
+fi
+
+# Test NOMAGIC for subdirs
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -g "$testdir" "*/does-not-exist" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "No magic in subdir test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs correctly
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "Subdirs test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs for invalid names
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/1" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Invalid subdir test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs with wildcard
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/*1_1" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`link1/file1_1'
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard subdir test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs with ?
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/*?_?" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard2 subdir test failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/file1_1" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`link1/file1_1'
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard3 subdir test failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*-/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard4 subdir test failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*-" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard5 subdir test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs with ?
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/*?_?" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "Wildcard6 subdir test failed" >> $logfile
+ result=1
+fi
+
+# Test subdirs with [ .. ]
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "*/file1_[12]" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "Brackets test failed" >> $logfile
+ result=1
+fi
+
+# Test ']' inside bracket expression
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "dir1/file1_[]12]" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "Brackets2 test failed" >> $logfile
+ result=1
+fi
+
+# Test tilde expansion
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -q -t "$testdir" "~" |
+sort >$testout
+echo ~ | $CMP - $testout >> $logfile || failed=1
+if test $failed -ne 0; then
+ if test -d ~; then
+ echo "Tilde test failed" >> $logfile
+ result=1
+ else
+ echo "Tilde test could not be run" >> $logfile
+ fi
+fi
+
+# Test tilde expansion with trailing slash
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -q -t "$testdir" "~/" |
+sort > $testout
+# Some shell incorrectly(?) convert ~/ into // if ~ expands to /.
+if test ~/ = //; then
+ echo / | $CMP - $testout >> $logfile || failed=1
+else
+ echo ~/ | $CMP - $testout >> $logfile || failed=1
+fi
+if test $failed -ne 0; then
+ if test -d ~/; then
+ echo "Tilde2 test failed" >> $logfile
+ result=1
+ else
+ echo "Tilde2 test could not be run" >> $logfile
+ fi
+fi
+
+# Test tilde expansion with username
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -q -t "$testdir" "~"$USER |
+sort > $testout
+eval echo ~$USER | $CMP - $testout >> $logfile || failed=1
+if test $failed -ne 0; then
+ if eval test -d ~$USER; then
+ echo "Tilde3 test failed" >> $logfile
+ result=1
+ else
+ echo "Tilde3 test could not be run" >> $logfile
+ fi
+fi
+
+# Tilde expansion shouldn't match a file
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -T "$testdir" "~file4" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Tilde4 test failed" >> $logfile
+ result=1
+fi
+
+# Matching \** should only find *file6
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "\**" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+EOF
+if test $failed -ne 0; then
+ echo "Star test failed" >> $logfile
+ result=1
+fi
+
+# ... unless NOESCAPE is used, in which case it should entries with a
+# leading \.
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -e "$testdir" "\**" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+EOF
+if test $failed -ne 0; then
+ echo "Star2 test failed" >> $logfile
+ result=1
+fi
+
+# Matching \*file6 should find *file6
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "\*file6" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+EOF
+if test $failed -ne 0; then
+ echo "Star3 test failed" >> $logfile
+ result=1
+fi
+
+# GLOB_BRACE alone
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" '\{file7\,\}' |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`{file7,}'
+EOF
+if test $failed -ne 0; then
+ echo "Brace4 test failed" >> $logfile
+ result=1
+fi
+
+# GLOB_BRACE and GLOB_NOESCAPE
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b -e "$testdir" '\{file9\,file9b\}' |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`\file9b\'
+EOF
+if test $failed -ne 0; then
+ echo "Brace5 test failed" >> $logfile
+ result=1
+fi
+
+# Escaped comma
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" '{filea\,}' |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`filea,'
+EOF
+if test $failed -ne 0; then
+ echo "Brace6 test failed" >> $logfile
+ result=1
+fi
+
+# Escaped closing brace
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -b "$testdir" '{fileb\}c}' |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`fileb}c'
+EOF
+if test $failed -ne 0; then
+ echo "Brace7 test failed" >> $logfile
+ result=1
+fi
+
+# Try a recursive failed search
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -e "$testdir" "a*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Star4 test failed" >> $logfile
+ result=1
+fi
+
+# ... with GLOB_ERR
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -E "$testdir" "a*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Star5 test failed" >> $logfile
+ result=1
+fi
+
+# Try a recursive search in unreadable directory
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "noread/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Star6 test failed" >> $logfile
+ result=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "noread*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_NOMATCH
+EOF
+if test $failed -ne 0; then
+ echo "Star6 test failed" >> $logfile
+ result=1
+fi
+
+# The following tests will fail if run as root.
+user=`id -un 2> /dev/null`
+if test -z "$user"; then
+ uid="$USER"
+fi
+if test "$user" != root; then
+ # ... with GLOB_ERR
+ ${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+ ${common_objpfx}posix/globtest -E "$testdir" "noread/*" |
+ sort > $testout
+ cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_ABORTED
+EOF
+
+ ${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+ ${common_objpfx}posix/globtest -E "$testdir" "noread*/*" |
+ sort > $testout
+ cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+GLOB_ABORTED
+EOF
+if test $failed -ne 0; then
+ echo "GLOB_ERR test failed" >> $logfile
+ result=1
+fi
+fi # not run as root
+
+# Try multiple patterns (GLOB_APPEND)
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest "$testdir" "file1" "*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`dir1/file1_1'
+`dir1/file1_2'
+`file1'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "GLOB_APPEND test failed" >> $logfile
+ result=1
+fi
+
+# Try multiple patterns (GLOB_APPEND) with offset (GLOB_DOOFFS)
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -o "$testdir" "file1" "*/*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`abc'
+`dir1/file1_1'
+`dir1/file1_2'
+`file1'
+`link1/file1_1'
+`link1/file1_2'
+EOF
+if test $failed -ne 0; then
+ echo "GLOB_APPEND2 test failed" >> $logfile
+ result=1
+fi
+
+# Test NOCHECK with non-existing file in subdir.
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -c "$testdir" "*/blahblah" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*/blahblah'
+EOF
+if test $failed -ne 0; then
+ echo "No check2 test failed" >> $logfile
+ result=1
+fi
+
+# Test [[:punct:]] not matching leading period.
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
+${common_objpfx}posix/globtest -c "$testdir" "[[:punct:]]*" |
+sort > $testout
+cat <<"EOF" | $CMP - $testout >> $logfile || failed=1
+`*file6'
+`-file3'
+`\file9b\'
+`\{file8\}'
+`\{file9\,file9b\}'
+`{file7,}'
+`~file4'
+EOF
+if test $failed -ne 0; then
+ echo "Punct test failed" >> $logfile
+ result=1
+fi
+
+if test $result -eq 0; then
+ chmod 777 $testdir/noread
+ rm -fr $testdir $testout
+ echo "All OK." > $logfile
+fi
+
+exit $result
+
+# Preserve executable bits for this shell script.
+Local Variables:
+eval:(defun frobme () (set-file-modes buffer-file-name file-mode))
+eval:(make-local-variable 'file-mode)
+eval:(setq file-mode (file-modes (buffer-file-name)))
+eval:(make-local-variable 'after-save-hook)
+eval:(add-hook 'after-save-hook 'frobme)
+End:
diff --git a/libc/posix/group_member.c b/libc/posix/group_member.c
new file mode 100644
index 000000000..7bd9c46ba
--- /dev/null
+++ b/libc/posix/group_member.c
@@ -0,0 +1,50 @@
+/* `group_member' -- test if process is in a given group.
+ Copyright (C) 1995, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 16 /* First guess. */
+#endif
+
+int
+__group_member (gid)
+ gid_t gid;
+{
+ int n, size;
+ gid_t *groups;
+
+ size = NGROUPS_MAX;
+ do
+ {
+ groups = __alloca (size * sizeof *groups);
+ n = __getgroups (size, groups);
+ size *= 2;
+ } while (n == size / 2);
+
+ while (n >= 0)
+ if (groups[n--] == gid)
+ return 1;
+
+ return 0;
+}
+weak_alias (__group_member, group_member)
diff --git a/libc/posix/init-posix.c b/libc/posix/init-posix.c
new file mode 100644
index 000000000..0c2b717e6
--- /dev/null
+++ b/libc/posix/init-posix.c
@@ -0,0 +1 @@
+/* Nothing to do. */
diff --git a/libc/posix/nanosleep.c b/libc/posix/nanosleep.c
new file mode 100644
index 000000000..7a2138b6f
--- /dev/null
+++ b/libc/posix/nanosleep.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <time.h>
+
+
+/* Pause execution for a number of nanoseconds. */
+int
+__libc_nanosleep (const struct timespec *requested_time,
+ struct timespec *remaining)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (nanosleep)
+
+weak_alias (__libc_nanosleep, __nanosleep)
+libc_hidden_def (__nanosleep)
+weak_alias (__libc_nanosleep, nanosleep)
+#include <stub-tag.h>
diff --git a/libc/posix/pathconf.c b/libc/posix/pathconf.c
new file mode 100644
index 000000000..6ac5d3190
--- /dev/null
+++ b/libc/posix/pathconf.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Get file-specific information about PATH. */
+long int
+__pathconf (path, name)
+ const char *path;
+ int name;
+{
+ if (path == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ return __fpathconf (0, name);
+}
+
+weak_alias (__pathconf, pathconf)
+
+stub_warning (pathconf)
+#include <stub-tag.h>
diff --git a/libc/posix/pause.c b/libc/posix/pause.c
new file mode 100644
index 000000000..2e34b436f
--- /dev/null
+++ b/libc/posix/pause.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Suspend the process until a signal arrives.
+ This is supposed to always return -1 and set errno to EINTR,
+ but rules were meant to be broken. */
+int
+pause ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (pause)
+#include <stub-tag.h>
diff --git a/libc/posix/posix_madvise.c b/libc/posix/posix_madvise.c
new file mode 100644
index 000000000..6f8d60f55
--- /dev/null
+++ b/libc/posix/posix_madvise.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1994, 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+/* Advise the system about particular usage patterns the program follows
+ for the region starting at ADDR and extending LEN bytes. */
+
+int
+posix_madvise (__ptr_t addr, size_t len, int advice)
+{
+ return ENOSYS;
+}
+stub_warning (posix_madvise)
+#include <stub-tag.h>
diff --git a/libc/posix/pread.c b/libc/posix/pread.c
new file mode 100644
index 000000000..5c79dd526
--- /dev/null
+++ b/libc/posix/pread.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Read NBYTES into BUF from FD at the given position OFFSET without
+ changing the file pointer. Return the number read or -1. */
+ssize_t
+__libc_pread (int fd, void *buf, size_t nbytes, off_t offset)
+{
+ if (nbytes == 0)
+ return 0;
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ if (buf == NULL || offset < 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+strong_alias (__libc_pread, __pread)
+weak_alias (__libc_pread, pread)
+stub_warning (pread)
+#include <stub-tag.h>
diff --git a/libc/posix/pread64.c b/libc/posix/pread64.c
new file mode 100644
index 000000000..68316579c
--- /dev/null
+++ b/libc/posix/pread64.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Read NBYTES into BUF from FD at the given position OFFSET without
+ changing the file pointer. Return the number read or -1. */
+ssize_t
+__libc_pread64 (int fd, void *buf, size_t nbytes, off64_t offset)
+{
+ if (nbytes == 0)
+ return 0;
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ if (buf == NULL || offset < 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+strong_alias (__libc_pread64, __pread64)
+weak_alias (__libc_pread64, pread64)
+stub_warning (pread64)
+#include <stub-tag.h>
diff --git a/libc/posix/ptestcases.h b/libc/posix/ptestcases.h
new file mode 100644
index 000000000..506b1cce0
--- /dev/null
+++ b/libc/posix/ptestcases.h
@@ -0,0 +1,326 @@
+ { 0, 0, "2.8.2 Regular Expression General Requirement", NULL, },
+ { 2, 4, "bb*", "abbbc", },
+ { 2, 2, "bb*", "ababbbc", },
+ { 7, 9, "A#*::", "A:A#:qA::qA#::qA##::q", },
+ { 1, 5, "A#*::", "A##::A#::qA::qA#:q", },
+ { 0, 0, "2.8.3.1.2 BRE Special Characters", NULL, },
+ { 0, 0, "GA108", NULL, },
+ { 2, 2, "\\.", "a.c", },
+ { 2, 2, "\\[", "a[c", },
+ { 2, 2, "\\\\", "a\\c", },
+ { 2, 2, "\\*", "a*c", },
+ { 2, 2, "\\^", "a^c", },
+ { 2, 2, "\\$", "a$c", },
+ { 7, 11, "X\\*Y\\*8", "Y*8X*8X*Y*8", },
+ { 0, 0, "GA109", NULL, },
+ { 2, 2, "[.]", "a.c", },
+ { 2, 2, "[[]", "a[c", },
+ { -1, -1, "[[]", "ac", },
+ { 2, 2, "[\\]", "a\\c", },
+ { 1, 1, "[\\a]", "abc", },
+ { 2, 2, "[\\.]", "a\\.c", },
+ { 2, 2, "[\\.]", "a.\\c", },
+ { 2, 2, "[*]", "a*c", },
+ { 2, 2, "[$]", "a$c", },
+ { 2, 2, "[X*Y8]", "7*8YX", },
+ { 0, 0, "GA110", NULL, },
+ { 2, 2, "*", "a*c", },
+ { 3, 4, "*a", "*b*a*c", },
+ { 1, 5, "**9=", "***9=9", },
+ { 0, 0, "GA111", NULL, },
+ { 1, 1, "^*", "*bc", },
+ { -1, -1, "^*", "a*c", },
+ { -1, -1, "^*", "^*ab", },
+ { 1, 5, "^**9=", "***9=", },
+ { -1, -1, "^*5<*9", "5<9*5<*9", },
+ { 0, 0, "GA112", NULL, },
+ { 2, 3, "\\(*b\\)", "a*b", },
+ { -1, -1, "\\(*b\\)", "ac", },
+ { 1, 6, "A\\(**9\\)=", "A***9=79", },
+ { 0, 0, "GA113(1)", NULL, },
+ { 1, 3, "\\(^*ab\\)", "*ab", },
+ { -1, -1, "\\(^*ab\\)", "^*ab", },
+ { -1, -1, "\\(^*b\\)", "a*b", },
+ { -1, -1, "\\(^*b\\)", "^*b", },
+ { 0, 0, "GA114", NULL, },
+ { 1, 3, "a^b", "a^b", },
+ { 1, 3, "a\\^b", "a^b", },
+ { 1, 1, "^^", "^bc", },
+ { 2, 2, "\\^", "a^c", },
+ { 1, 1, "[c^b]", "^abc", },
+ { 1, 1, "[\\^ab]", "^ab", },
+ { 2, 2, "[\\^ab]", "c\\d", },
+ { -1, -1, "[^^]", "^", },
+ { 1, 3, "\\(a^b\\)", "a^b", },
+ { 1, 3, "\\(a\\^b\\)", "a^b", },
+ { 2, 2, "\\(\\^\\)", "a^b", },
+ { 0, 0, "GA115", NULL, },
+ { 3, 3, "$$", "ab$", },
+ { -1, -1, "$$", "$ab", },
+ { 2, 3, "$c", "a$c", },
+ { 2, 2, "[$]", "a$c", },
+ { 1, 2, "\\$a", "$a", },
+ { 3, 3, "\\$$", "ab$", },
+ { 2, 6, "A\\([34]$[34]\\)B", "XA4$3BY", },
+ { 0, 0, "2.8.3.1.3 Periods in BREs", NULL, },
+ { 0, 0, "GA116", NULL, },
+ { 1, 1, ".", "abc", },
+ { -1, -1, ".ab", "abc", },
+ { 1, 3, "ab.", "abc", },
+ { 1, 3, "a.b", "a,b", },
+ { -1, -1, ".......", "PqRs6", },
+ { 1, 7, ".......", "PqRs6T8", },
+ { 0, 0, "2.8.3.2 RE Bracket Expression", NULL, },
+ { 0, 0, "GA118", NULL, },
+ { 2, 2, "[abc]", "xbyz", },
+ { -1, -1, "[abc]", "xyz", },
+ { 2, 2, "[abc]", "xbay", },
+ { 0, 0, "GA119", NULL, },
+ { 2, 2, "[^a]", "abc", },
+ { 4, 4, "[^]cd]", "cd]ef", },
+ { 2, 2, "[^abc]", "axyz", },
+ { -1, -1, "[^abc]", "abc", },
+ { 3, 3, "[^[.a.]b]", "abc", },
+ { 3, 3, "[^[=a=]b]", "abc", },
+ { 2, 2, "[^-ac]", "abcde-", },
+ { 2, 2, "[^ac-]", "abcde-", },
+ { 3, 3, "[^a-b]", "abcde", },
+ { 3, 3, "[^a-bd-e]", "dec", },
+ { 2, 2, "[^---]", "-ab", },
+ { 16, 16, "[^a-zA-Z0-9]", "pqrstVWXYZ23579#", },
+ { 0, 0, "GA120(1)", NULL, },
+ { 3, 3, "[]a]", "cd]ef", },
+ { 1, 1, "[]-a]", "a_b", },
+ { 3, 3, "[][.-.]-0]", "ab0-]", },
+ { 1, 1, "[]^a-z]", "string", },
+ { 0, 0, "GA120(2)", NULL, },
+ { 4, 4, "[^]cd]", "cd]ef", },
+ { 0, 0, "[^]]*", "]]]]]]]]X", },
+ { 0, 0, "[^]]*", "]]]]]]]]", },
+ { 9, 9, "[^]]\\{1,\\}", "]]]]]]]]X", },
+ { -1, -1, "[^]]\\{1,\\}", "]]]]]]]]", },
+ { 0, 0, "GA120(3)", NULL, },
+ { 3, 3, "[c[.].]d]", "ab]cd", },
+ { 2, 8, "[a-z]*[[.].]][A-Z]*", "Abcd]DEFg", },
+ { 0, 0, "GA121", NULL, },
+ { 2, 2, "[[.a.]b]", "Abc", },
+ { 1, 1, "[[.a.]b]", "aBc", },
+ { -1, -1, "[[.a.]b]", "ABc", },
+ { 3, 3, "[^[.a.]b]", "abc", },
+ { 3, 3, "[][.-.]-0]", "ab0-]", },
+ { 3, 3, "[A-[.].]c]", "ab]!", },
+ { 0, 0, "GA122", NULL, },
+ { -2, -2, "[[.ch.]]", "abc", },
+ { -2, -2, "[[.ab.][.CD.][.EF.]]", "yZabCDEFQ9", },
+ { 0, 0, "GA125", NULL, },
+ { 2, 2, "[[=a=]b]", "Abc", },
+ { 1, 1, "[[=a=]b]", "aBc", },
+ { -1, -1, "[[=a=]b]", "ABc", },
+ { 3, 3, "[^[=a=]b]", "abc", },
+ { 0, 0, "GA126", NULL, },
+ { 0, 0, NULL, "the expected result for [[:alnum:]]* is 2-7 which is wrong" },
+ { 0, 0, "[[:alnum:]]*", " aB28gH", },
+ { 2, 7, "[[:alnum:]][[:alnum:]]*", " aB28gH", },
+ { 0, 0, NULL, "the expected result for [^[:alnum:]]* is 2-5 which is wrong" },
+ { 0, 0, "[^[:alnum:]]*", "2 ,a", },
+ { 2, 5, "[^[:alnum:]][^[:alnum:]]*", "2 ,a", },
+ { 0, 0, NULL, "the expected result for [[:alpha:]]* is 2-5 which is wrong" },
+ { 0, 0, "[[:alpha:]]*", " aBgH2", },
+ { 2, 5, "[[:alpha:]][[:alpha:]]*", " aBgH2", },
+ { 1, 6, "[^[:alpha:]]*", "2 8,a", },
+ { 1, 2, "[[:blank:]]*", " \r", },
+ { 1, 8, "[^[:blank:]]*", "aB28gH, ", },
+ { 1, 2, "[[:cntrl:]]*", "  ", },
+ { 1, 8, "[^[:cntrl:]]*", "aB2 8gh,", },
+ { 0, 0, NULL, "the expected result for [[:digit:]]* is 2-3 which is wrong" },
+ { 0, 0, "[[:digit:]]*", "a28", },
+ { 2, 3, "[[:digit:]][[:digit:]]*", "a28", },
+ { 1, 8, "[^[:digit:]]*", "aB gH,", },
+ { 1, 7, "[[:graph:]]*", "aB28gH, ", },
+ { 1, 3, "[^[:graph:]]*", " ,", },
+ { 1, 2, "[[:lower:]]*", "agB", },
+ { 1, 8, "[^[:lower:]]*", "B2 8H,a", },
+ { 1, 8, "[[:print:]]*", "aB2 8gH, ", },
+ { 1, 2, "[^[:print:]]*", "  ", },
+ { 0, 0, NULL, "the expected result for [[:punct:]]* is 2-2 which is wrong" },
+ { 0, 0, "[[:punct:]]*", "a,2", },
+ { 2, 3, "[[:punct:]][[:punct:]]*", "a,,2", },
+ { 1, 9, "[^[:punct:]]*", "aB2 8gH", },
+ { 1, 3, "[[:space:]]*", " \r", },
+ { 0, 0, NULL, "the expected result for [^[:space:]]* is 2-9 which is wrong" },
+ { 0, 0, "[^[:space:]]*", " aB28gH, ", },
+ { 2, 9, "[^[:space:]][^[:space:]]*", " aB28gH, ", },
+ { 0, 0, NULL, "the expected result for [[:upper:]]* is 2-3 which is wrong" },
+ { 0, 0, "[[:upper:]]*", "aBH2", },
+ { 2, 3, "[[:upper:]][[:upper:]]*", "aBH2", },
+ { 1, 8, "[^[:upper:]]*", "a2 8g,B", },
+ { 0, 0, NULL, "the expected result for [[:xdigit:]]* is 2-5 which is wrong" },
+ { 0, 0, "[[:xdigit:]]*", "gaB28h", },
+ { 2, 5, "[[:xdigit:]][[:xdigit:]]*", "gaB28h", },
+ { 0, 0, NULL, "the expected result for [^[:xdigit:]]* is 2-7 which is wrong" },
+ { 2, 7, "[^[:xdigit:]][^[:xdigit:]]*", "a gH,2", },
+ { 0, 0, "GA127", NULL, },
+ { -2, -2, "[b-a]", "abc", },
+ { 1, 1, "[a-c]", "bbccde", },
+ { 2, 2, "[a-b]", "-bc", },
+ { 3, 3, "[a-z0-9]", "AB0", },
+ { 3, 3, "[^a-b]", "abcde", },
+ { 3, 3, "[^a-bd-e]", "dec", },
+ { 1, 1, "[]-a]", "a_b", },
+ { 2, 2, "[+--]", "a,b", },
+ { 2, 2, "[--/]", "a.b", },
+ { 2, 2, "[^---]", "-ab", },
+ { 3, 3, "[][.-.]-0]", "ab0-]", },
+ { 3, 3, "[A-[.].]c]", "ab]!", },
+ { 2, 6, "bc[d-w]xy", "abchxyz", },
+ { 0, 0, "GA129", NULL, },
+ { 1, 1, "[a-cd-f]", "dbccde", },
+ { -1, -1, "[a-ce-f]", "dBCCdE", },
+ { 2, 4, "b[n-zA-M]Y", "absY9Z", },
+ { 2, 4, "b[n-zA-M]Y", "abGY9Z", },
+ { 0, 0, "GA130", NULL, },
+ { 3, 3, "[-xy]", "ac-", },
+ { 2, 4, "c[-xy]D", "ac-D+", },
+ { 2, 2, "[--/]", "a.b", },
+ { 2, 4, "c[--/]D", "ac.D+b", },
+ { 2, 2, "[^-ac]", "abcde-", },
+ { 1, 3, "a[^-ac]c", "abcde-", },
+ { 3, 3, "[xy-]", "zc-", },
+ { 2, 4, "c[xy-]7", "zc-786", },
+ { 2, 2, "[^ac-]", "abcde-", },
+ { 2, 4, "a[^ac-]c", "5abcde-", },
+ { 2, 2, "[+--]", "a,b", },
+ { 2, 4, "a[+--]B", "Xa,By", },
+ { 2, 2, "[^---]", "-ab", },
+ { 4, 6, "X[^---]Y", "X-YXaYXbY", },
+ { 0, 0, "2.8.3.3 BREs Matching Multiple Characters", NULL, },
+ { 0, 0, "GA131", NULL, },
+ { 3, 4, "cd", "abcdeabcde", },
+ { 1, 2, "ag*b", "abcde", },
+ { -1, -1, "[a-c][e-f]", "abcdef", },
+ { 3, 4, "[a-c][e-f]", "acbedf", },
+ { 4, 8, "abc*XYZ", "890abXYZ#*", },
+ { 4, 9, "abc*XYZ", "890abcXYZ#*", },
+ { 4, 15, "abc*XYZ", "890abcccccccXYZ#*", },
+ { -1, -1, "abc*XYZ", "890abc*XYZ#*", },
+ { 0, 0, "GA132", NULL, },
+ { 2, 4, "\\(*bc\\)", "a*bc", },
+ { 1, 2, "\\(ab\\)", "abcde", },
+ { 1, 10, "\\(a\\(b\\(c\\(d\\(e\\(f\\(g\\)h\\(i\\(j\\)\\)\\)\\)\\)\\)\\)\\)", "abcdefghijk", },
+ { 3, 8, "43\\(2\\(6\\)*0\\)AB", "654320ABCD", },
+ { 3, 9, "43\\(2\\(7\\)*0\\)AB", "6543270ABCD", },
+ { 3, 12, "43\\(2\\(7\\)*0\\)AB", "6543277770ABCD", },
+ { 0, 0, "GA133", NULL, },
+ { 1, 10, "\\(a\\(b\\(c\\(d\\(e\\(f\\(g\\)h\\(i\\(j\\)\\)\\)\\)\\)\\)\\)\\)", "abcdefghijk", },
+ { -1, -1, "\\(a\\(b\\(c\\(d\\(e\\(f\\(g\\)h\\(i\\(k\\)\\)\\)\\)\\)\\)\\)\\)", "abcdefghijk", },
+ { 0, 0, "GA134", NULL, },
+ { 2, 4, "\\(bb*\\)", "abbbc", },
+ { 2, 2, "\\(bb*\\)", "ababbbc", },
+ { 1, 6, "a\\(.*b\\)", "ababbbc", },
+ { 1, 2, "a\\(b*\\)", "ababbbc", },
+ { 1, 20, "a\\(.*b\\)c", "axcaxbbbcsxbbbbbbbbc", },
+ { 0, 0, "GA135", NULL, },
+ { 1, 7, "\\(a\\(b\\(c\\(d\\(e\\)\\)\\)\\)\\)\\4", "abcdededede", },
+ { 0, 0, NULL, "POSIX does not really specify whether a\\(b\\)*c\\1 matches acb." },
+ { 0, 0, NULL, "back references are supposed to expand to the last match, but what" },
+ { 0, 0, NULL, "if there never was a match as in this case?" },
+ { -1, -1, "a\\(b\\)*c\\1", "acb", },
+ { 1, 11, "\\(a\\(b\\(c\\(d\\(e\\(f\\(g\\)h\\(i\\(j\\)\\)\\)\\)\\)\\)\\)\\)\\9", "abcdefghijjk", },
+ { 0, 0, "GA136", NULL, },
+ { 0, 0, NULL, "These two tests have the same problem as the test in GA135. No match" },
+ { 0, 0, NULL, "of a subexpression, why should the back reference be usable?" },
+ { 0, 0, NULL, "1 2 a\\(b\\)*c\\1 acb" },
+ { 0, 0, NULL, "4 7 a\\(b\\(c\\(d\\(f\\)*\\)\\)\\)\\4¦xYzabcdePQRST" },
+ { -1, -1, "a\\(b\\)*c\\1", "acb", },
+ { -1, -1, "a\\(b\\(c\\(d\\(f\\)*\\)\\)\\)\\4", "xYzabcdePQRST", },
+ { 0, 0, "GA137", NULL, },
+ { -2, -2, "\\(a\\(b\\)\\)\\3", "foo", },
+ { -2, -2, "\\(a\\(b\\)\\)\\(a\\(b\\)\\)\\5", "foo", },
+ { 0, 0, "GA138", NULL, },
+ { 1, 2, "ag*b", "abcde", },
+ { 1, 10, "a.*b", "abababvbabc", },
+ { 2, 5, "b*c", "abbbcdeabbbbbbcde", },
+ { 2, 5, "bbb*c", "abbbcdeabbbbbbcde", },
+ { 1, 5, "a\\(b\\)*c\\1", "abbcbbb", },
+ { -1, -1, "a\\(b\\)*c\\1", "abbdbd", },
+ { 0, 0, "\\([a-c]*\\)\\1", "abcacdef", },
+ { 1, 6, "\\([a-c]*\\)\\1", "abcabcabcd", },
+ { 1, 2, "a^*b", "ab", },
+ { 1, 5, "a^*b", "a^^^b", },
+ { 0, 0, "GA139", NULL, },
+ { 1, 2, "a\\{2\\}", "aaaa", },
+ { 1, 7, "\\([a-c]*\\)\\{0,\\}", "aabcaab", },
+ { 1, 2, "\\(a\\)\\1\\{1,2\\}", "aabc", },
+ { 1, 3, "\\(a\\)\\1\\{1,2\\}", "aaaabc", },
+ { 0, 0, NULL, "the expression \\(\\(a\\)\\1\\)\\{1,2\\} is ill-formed, using \\2" },
+ { 1, 4, "\\(\\(a\\)\\2\\)\\{1,2\\}", "aaaabc", },
+ { 0, 0, "GA140", NULL, },
+ { 1, 2, "a\\{2\\}", "aaaa", },
+ { -1, -1, "a\\{2\\}", "abcd", },
+ { 0, 0, "a\\{0\\}", "aaaa", },
+ { 1, 64, "a\\{64\\}", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", },
+ { 0, 0, "GA141", NULL, },
+ { 1, 7, "\\([a-c]*\\)\\{0,\\}", "aabcaab", },
+ { 0, 0, NULL, "the expected result for \\([a-c]*\\)\\{2,\\} is failure which isn't correct" },
+ { 1, 3, "\\([a-c]*\\)\\{2,\\}", "abcdefg", },
+ { 1, 3, "\\([a-c]*\\)\\{1,\\}", "abcdefg", },
+ { -1, -1, "a\\{64,\\}", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", },
+ { 0, 0, "GA142", NULL, },
+ { 1, 3, "a\\{2,3\\}", "aaaa", },
+ { -1, -1, "a\\{2,3\\}", "abcd", },
+ { 0, 0, "\\([a-c]*\\)\\{0,0\\}", "foo", },
+ { 1, 63, "a\\{1,63\\}", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", },
+ { 0, 0, "2.8.3.4 BRE Precedence", NULL, },
+ { 0, 0, "GA143", NULL, },
+ { 0, 0, NULL, "There are numerous bugs in the original version." },
+ { 2, 19, "\\^\\[[[.].]]\\\\(\\\\1\\\\)\\*\\\\{1,2\\\\}\\$", "a^[]\\(\\1\\)*\\{1,2\\}$b", },
+ { 1, 6, "[[=*=]][[=\\=]][[=]=]][[===]][[...]][[:punct:]]", "*\\]=.;", },
+ { 1, 6, "[$\\(*\\)^]*", "$\\()*^", },
+ { 1, 1, "[\\1]", "1", },
+ { 1, 1, "[\\{1,2\\}]", "{", },
+ { 0, 0, NULL, "the expected result for \\(*\\)*\\1* is 2-2 which isn't correct" },
+ { 0, 0, "\\(*\\)*\\1*", "a*b*11", },
+ { 2, 3, "\\(*\\)*\\1*b", "a*b*11", },
+ { 0, 0, NULL, "the expected result for \\(a\\(b\\{1,2\\}\\)\\{1,2\\}\\) is 1-5 which isn't correct" },
+ { 1, 3, "\\(a\\(b\\{1,2\\}\\)\\{1,2\\}\\)", "abbab", },
+ { 1, 5, "\\(a\\(b\\{1,2\\}\\)\\)\\{1,2\\}", "abbab", },
+ { 1, 1, "^\\(^\\(^a$\\)$\\)$", "a", },
+ { 1, 2, "\\(a\\)\\1$", "aa", },
+ { 1, 3, "ab*", "abb", },
+ { 1, 4, "ab\\{2,4\\}", "abbbc", },
+ { 0, 0, "2.8.3.5 BRE Expression Anchoring", NULL, },
+ { 0, 0, "GA144", NULL, },
+ { 1, 1, "^a", "abc", },
+ { -1, -1, "^b", "abc", },
+ { -1, -1, "^[a-zA-Z]", "99Nine", },
+ { 1, 4, "^[a-zA-Z]*", "Nine99", },
+ { 0, 0, "GA145(1)", NULL, },
+ { 1, 2, "\\(^a\\)\\1", "aabc", },
+ { -1, -1, "\\(^a\\)\\1", "^a^abc", },
+ { 1, 2, "\\(^^a\\)", "^a", },
+ { 1, 1, "\\(^^\\)", "^^", },
+ { 1, 3, "\\(^abc\\)", "abcdef", },
+ { -1, -1, "\\(^def\\)", "abcdef", },
+ { 0, 0, "GA146", NULL, },
+ { 3, 3, "a$", "cba", },
+ { -1, -1, "a$", "abc", },
+ { 5, 7, "[a-z]*$", "99ZZxyz", },
+ { 0, 0, NULL, "the expected result for [a-z]*$ is failure which isn't correct" },
+ { 10, 9, "[a-z]*$", "99ZZxyz99", },
+ { 3, 3, "$$", "ab$", },
+ { -1, -1, "$$", "$ab", },
+ { 3, 3, "\\$$", "ab$", },
+ { 0, 0, "GA147(1)", NULL, },
+ { -1, -1, "\\(a$\\)\\1", "bcaa", },
+ { -1, -1, "\\(a$\\)\\1", "ba$", },
+ { -1, -1, "\\(ab$\\)", "ab$", },
+ { 1, 2, "\\(ab$\\)", "ab", },
+ { 4, 6, "\\(def$\\)", "abcdef", },
+ { -1, -1, "\\(abc$\\)", "abcdef", },
+ { 0, 0, "GA148", NULL, },
+ { 0, 0, "^$", "", },
+ { 1, 3, "^abc$", "abc", },
+ { -1, -1, "^xyz$", "^xyz^", },
+ { -1, -1, "^234$", "^234$", },
+ { 1, 9, "^[a-zA-Z0-9]*$", "2aA3bB9zZ", },
+ { -1, -1, "^[a-z0-9]*$", "2aA3b#B9zZ", },
diff --git a/libc/posix/pwrite.c b/libc/posix/pwrite.c
new file mode 100644
index 000000000..ec35ecea9
--- /dev/null
+++ b/libc/posix/pwrite.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Write NBYTES of BUF to FD at given position OFFSET without changing
+ the file position. Return the number written, or -1. */
+ssize_t
+__libc_pwrite (int fd, const void *buf, size_t nbytes, off_t offset)
+{
+ if (nbytes == 0)
+ return 0;
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ if (buf == NULL || offset < 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+strong_alias (__libc_pwrite, __pwrite)
+weak_alias (__libc_pwrite, pwrite)
+stub_warning (pwrite)
+#include <stub-tag.h>
diff --git a/libc/posix/pwrite64.c b/libc/posix/pwrite64.c
new file mode 100644
index 000000000..dd14aa0bd
--- /dev/null
+++ b/libc/posix/pwrite64.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 1991,1995,1996,1997,1999,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Write NBYTES of BUF to FD at given position OFFSET without changing
+ the file position. Return the number written, or -1. */
+ssize_t
+__libc_pwrite64 (int fd, const void *buf, size_t nbytes, off64_t offset)
+{
+ if (nbytes == 0)
+ return 0;
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ if (buf == NULL || offset < 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+strong_alias (__libc_pwrite64, __pwrite64)
+libc_hidden_def (__pwrite64)
+weak_alias (__libc_pwrite64, pwrite64)
+stub_warning (pwrite64)
+#include <stub-tag.h>
diff --git a/libc/posix/re_comp.h b/libc/posix/re_comp.h
new file mode 100644
index 000000000..49114479c
--- /dev/null
+++ b/libc/posix/re_comp.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _RE_COMP_H
+#define _RE_COMP_H 1
+
+/* This is only a wrapper around the <regex.h> file. XPG4.2 mentions
+ this name. */
+#include <regex.h>
+
+#endif /* re_comp.h */
diff --git a/libc/posix/regcomp.c b/libc/posix/regcomp.c
new file mode 100644
index 000000000..78a1218cf
--- /dev/null
+++ b/libc/posix/regcomp.c
@@ -0,0 +1,3800 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+ const re_dfastate_t *init_state,
+ char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif /* RE_ENABLE_I18N */
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t preorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+ bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
+static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+ int node, int root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static int fetch_number (re_string_t *input, re_token_t *token,
+ reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax) internal_function;
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+ re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax,
+ reg_errcode_t *err);
+static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token, int token_len,
+ re_dfa_t *dfa,
+ reg_syntax_t syntax,
+ int accept_hyphen);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token);
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *equiv_class_alloc,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *char_class_alloc,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+ RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ int non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+const char __re_error_msgid[] attribute_hidden =
+ {
+#define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+const size_t __re_error_msgid_idx[] attribute_hidden =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length LENGTH) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ size_t length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub, unless RE_NO_SUB is set. */
+ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ char *fastmap = bufp->fastmap;
+
+ memset (fastmap, '\0', sizeof (char) * SBC_MAX);
+ re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
+ if (dfa->init_state != dfa->init_state_word)
+ re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
+ if (dfa->init_state != dfa->init_state_nl)
+ re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
+ if (dfa->init_state != dfa->init_state_begbuf)
+ re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
+ bufp->fastmap_accurate = 1;
+ return 0;
+}
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+static inline void
+__attribute ((always_inline))
+re_set_fastmap (char *fastmap, int icase, int ch)
+{
+ fastmap[ch] = 1;
+ if (icase)
+ fastmap[tolower (ch)] = 1;
+}
+
+/* Helper function for re_compile_fastmap.
+ Compile fastmap for the initial_state INIT_STATE. */
+
+static void
+re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
+ char *fastmap)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+ int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ int node = init_state->nodes.elems[node_cnt];
+ re_token_type_t type = dfa->nodes[node].type;
+
+ if (type == CHARACTER)
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+#ifdef RE_ENABLE_I18N
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ unsigned char *buf = alloca (dfa->mb_cur_max), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+ p = buf;
+ *p++ = dfa->nodes[node].opr.c;
+ while (++node < dfa->nodes_len
+ && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].mb_partial)
+ *p++ = dfa->nodes[node].opr.c;
+ memset (&state, '\0', sizeof (state));
+ if (mbrtowc (&wc, (const char *) buf, p - buf,
+ &state) == p - buf
+ && (__wcrtomb ((char *) buf, towlower (wc), &state)
+ != (size_t) -1))
+ re_set_fastmap (fastmap, 0, buf[0]);
+ }
+#endif
+ }
+ else if (type == SIMPLE_BRACKET)
+ {
+ int i, ch;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ {
+ int j;
+ bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (w & ((bitset_word_t) 1 << j))
+ re_set_fastmap (fastmap, icase, ch);
+ }
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == COMPLEX_BRACKET)
+ {
+ int i;
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+ if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes
+ || cset->nranges || cset->nchar_classes)
+ {
+# ifdef _LIBC
+ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0)
+ {
+ /* In this case we want to catch the bytes which are
+ the first byte of any collation elements.
+ e.g. In da_DK, we want to catch 'a' since "aa"
+ is a valid collation element, and don't catch
+ 'b' since 'b' is the only collation element
+ which starts from 'b'. */
+ const int32_t *table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ for (i = 0; i < SBC_MAX; ++i)
+ if (table[i] < 0)
+ re_set_fastmap (fastmap, icase, i);
+ }
+# else
+ if (dfa->mb_cur_max > 1)
+ for (i = 0; i < SBC_MAX; ++i)
+ if (__btowc (i) == WEOF)
+ re_set_fastmap (fastmap, icase, i);
+# endif /* not _LIBC */
+ }
+ for (i = 0; i < cset->nmbchars; ++i)
+ {
+ char buf[256];
+ mbstate_t state;
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+ re_set_fastmap (fastmap, 0, *(unsigned char *) buf);
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ else if (type == OP_PERIOD
+#ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+#endif /* RE_ENABLE_I18N */
+ || type == END_OF_RE)
+ {
+ memset (fastmap, '\1', sizeof (char) * SBC_MAX);
+ if (type == END_OF_RE)
+ bufp->can_be_null = 1;
+ return;
+ }
+ }
+}
+
+/* Entry point for POSIX code. */
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' to an allocated space for the fastmap;
+ `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (preg, pattern, cflags)
+ regex_t *__restrict preg;
+ const char *__restrict pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
+ : RE_SYNTAX_POSIX_BASIC);
+
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Try to allocate space for the fastmap. */
+ preg->fastmap = re_malloc (char, SBC_MAX);
+ if (BE (preg->fastmap == NULL, 0))
+ return REG_ESPACE;
+
+ syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+ preg->no_sub = !!(cflags & REG_NOSUB);
+ preg->translate = NULL;
+
+ ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN)
+ ret = REG_EPAREN;
+
+ /* We have already checked preg->fastmap != NULL. */
+ if (BE (ret == REG_NOERROR, 1))
+ /* Compute the fastmap now, since regexec cannot modify the pattern
+ buffer. This function never fails in this implementation. */
+ (void) re_compile_fastmap (preg);
+ else
+ {
+ /* Some error occurred while compiling the expression. */
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+ }
+
+ return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *__restrict preg;
+ char *__restrict errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (BE (errcode < 0
+ || errcode >= (int) (sizeof (__re_error_msgid_idx)
+ / sizeof (__re_error_msgid_idx[0])), 0))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (BE (errbuf_size != 0, 1))
+ {
+ if (BE (msg_size > errbuf_size, 0))
+ {
+#if defined HAVE_MEMPCPY || defined _LIBC
+ *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+#endif
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+#ifdef RE_ENABLE_I18N
+/* This static array is used for the map to single-byte characters when
+ UTF-8 is used. Otherwise we would allocate memory just to initialize
+ it the same all the time. UTF-8 is the preferred encoding so this is
+ a worthwhile optimization. */
+static const bitset_t utf8_sb_map =
+{
+ /* Set the first 128 bits. */
+ [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
+};
+#endif
+
+
+static void
+free_dfa_content (re_dfa_t *dfa)
+{
+ int i, j;
+
+ if (dfa->nodes)
+ for (i = 0; i < dfa->nodes_len; ++i)
+ free_token (dfa->nodes + i);
+ re_free (dfa->nexts);
+ for (i = 0; i < dfa->nodes_len; ++i)
+ {
+ if (dfa->eclosures != NULL)
+ re_node_set_free (dfa->eclosures + i);
+ if (dfa->inveclosures != NULL)
+ re_node_set_free (dfa->inveclosures + i);
+ if (dfa->edests != NULL)
+ re_node_set_free (dfa->edests + i);
+ }
+ re_free (dfa->edests);
+ re_free (dfa->eclosures);
+ re_free (dfa->inveclosures);
+ re_free (dfa->nodes);
+
+ if (dfa->state_table)
+ for (i = 0; i <= dfa->state_hash_mask; ++i)
+ {
+ struct re_state_table_entry *entry = dfa->state_table + i;
+ for (j = 0; j < entry->num; ++j)
+ {
+ re_dfastate_t *state = entry->array[j];
+ free_state (state);
+ }
+ re_free (entry->array);
+ }
+ re_free (dfa->state_table);
+#ifdef RE_ENABLE_I18N
+ if (dfa->sb_char != utf8_sb_map)
+ re_free (dfa->sb_char);
+#endif
+ re_free (dfa->subexp_map);
+#ifdef DEBUG
+ re_free (dfa->re_str);
+#endif
+
+ re_free (dfa);
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ if (BE (dfa != NULL, 1))
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+
+ re_free (preg->translate);
+ preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+# ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec above without link errors. */
+weak_function
+# endif
+re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+ char *fastmap;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (re_comp_buf.buffer)
+ {
+ fastmap = re_comp_buf.fastmap;
+ re_comp_buf.fastmap = NULL;
+ __regfree (&re_comp_buf);
+ memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
+ re_comp_buf.fastmap = fastmap;
+ }
+
+ if (re_comp_buf.fastmap == NULL)
+ {
+ re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
+ if (re_comp_buf.fastmap == NULL)
+ return (char *) gettext (__re_error_msgid
+ + __re_error_msgid_idx[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+#ifdef _LIBC
+libc_freeres_fn (free_mem)
+{
+ __regfree (&re_comp_buf);
+}
+#endif
+
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point.
+ Compile the regular expression PATTERN, whose length is LENGTH.
+ SYNTAX indicate regular expression's syntax. */
+
+static reg_errcode_t
+re_compile_internal (regex_t *preg, const char * pattern, size_t length,
+ reg_syntax_t syntax)
+{
+ reg_errcode_t err = REG_NOERROR;
+ re_dfa_t *dfa;
+ re_string_t regexp;
+
+ /* Initialize the pattern buffer. */
+ preg->fastmap_accurate = 0;
+ preg->syntax = syntax;
+ preg->not_bol = preg->not_eol = 0;
+ preg->used = 0;
+ preg->re_nsub = 0;
+ preg->can_be_null = 0;
+ preg->regs_allocated = REGS_UNALLOCATED;
+
+ /* Initialize the dfa. */
+ dfa = (re_dfa_t *) preg->buffer;
+ if (BE (preg->allocated < sizeof (re_dfa_t), 0))
+ {
+ /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. If ->buffer is NULL this
+ is a simple allocation. */
+ dfa = re_realloc (preg->buffer, re_dfa_t, 1);
+ if (dfa == NULL)
+ return REG_ESPACE;
+ preg->allocated = sizeof (re_dfa_t);
+ preg->buffer = (unsigned char *) dfa;
+ }
+ preg->used = sizeof (re_dfa_t);
+
+ err = init_dfa (dfa, length);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+#ifdef DEBUG
+ /* Note: length+1 will not overflow since it is checked in init_dfa. */
+ dfa->re_str = re_malloc (char, length + 1);
+ strncpy (dfa->re_str, pattern, length + 1);
+#endif
+
+ __libc_lock_init (dfa->lock);
+
+ err = re_string_construct (&regexp, pattern, length, preg->translate,
+ syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_compile_internal_free_return:
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+
+ /* Parse the regular expression, and build a structure tree. */
+ preg->re_nsub = 0;
+ dfa->str_tree = parse (&regexp, preg, syntax, &err);
+ if (BE (dfa->str_tree == NULL, 0))
+ goto re_compile_internal_free_return;
+
+ /* Analyze the tree and create the nfa. */
+ err = analyze (preg);
+ if (BE (err != REG_NOERROR, 0))
+ goto re_compile_internal_free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* If possible, do searching in single byte encoding to speed things up. */
+ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
+ optimize_utf8 (dfa);
+#endif
+
+ /* Then create the initial state of the dfa. */
+ err = create_initial_state (dfa);
+
+ /* Release work areas. */
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ }
+
+ return err;
+}
+
+/* Initialize DFA. We use the length of the regular expression PAT_LEN
+ as the initial length of some arrays. */
+
+static reg_errcode_t
+init_dfa (re_dfa_t *dfa, size_t pat_len)
+{
+ unsigned int table_size;
+#ifndef _LIBC
+ char *codeset_name;
+#endif
+
+ memset (dfa, '\0', sizeof (re_dfa_t));
+
+ /* Force allocation of str_tree_storage the first time. */
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+
+ /* Avoid overflows. */
+ if (pat_len == SIZE_MAX)
+ return REG_ESPACE;
+
+ dfa->nodes_alloc = pat_len + 1;
+ dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
+
+ /* table_size = 2 ^ ceil(log pat_len) */
+ for (table_size = 1; ; table_size <<= 1)
+ if (table_size > pat_len)
+ break;
+
+ dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
+ dfa->state_hash_mask = table_size - 1;
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+#ifdef _LIBC
+ if (dfa->mb_cur_max == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
+#else
+# ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+# else
+ codeset_name = getenv ("LC_ALL");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LC_CTYPE");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LANG");
+ if (codeset_name == NULL)
+ codeset_name = "";
+ else if (strchr (codeset_name, '.') != NULL)
+ codeset_name = strchr (codeset_name, '.') + 1;
+# endif
+
+ if (strcasecmp (codeset_name, "UTF-8") == 0
+ || strcasecmp (codeset_name, "UTF8") == 0)
+ dfa->is_utf8 = 1;
+
+ /* We check exhaustively in the loop below if this charset is a
+ superset of ASCII. */
+ dfa->map_notascii = 0;
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+ else
+ {
+ int i, j, ch;
+
+ dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+ if (BE (dfa->sb_char == NULL, 0))
+ return REG_ESPACE;
+
+ /* Set the bits corresponding to single byte chars. */
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ {
+ wint_t wch = __btowc (ch);
+ if (wch != WEOF)
+ dfa->sb_char[i] |= (bitset_word_t) 1 << j;
+# ifndef _LIBC
+ if (isascii (ch) && wch != ch)
+ dfa->map_notascii = 1;
+# endif
+ }
+ }
+ }
+#endif
+
+ if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+/* Initialize WORD_CHAR table, which indicate which character is
+ "word". In this case "word" means that it is the word construction
+ character used by some operators like "\<", "\>", etc. */
+
+static void
+internal_function
+init_word_char (re_dfa_t *dfa)
+{
+ int i, j, ch;
+ dfa->word_ops_used = 1;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (isalnum (ch) || ch == '_')
+ dfa->word_char[i] |= (bitset_word_t) 1 << j;
+}
+
+/* Free the work area which are only used while compiling. */
+
+static void
+free_workarea_compile (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_storage_t *storage, *next;
+ for (storage = dfa->str_tree_storage; storage; storage = next)
+ {
+ next = storage->next;
+ re_free (storage);
+ }
+ dfa->str_tree_storage = NULL;
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+ dfa->str_tree = NULL;
+ re_free (dfa->org_indices);
+ dfa->org_indices = NULL;
+}
+
+/* Create initial states for all contexts. */
+
+static reg_errcode_t
+create_initial_state (re_dfa_t *dfa)
+{
+ int first, i;
+ reg_errcode_t err;
+ re_node_set init_nodes;
+
+ /* Initial states have the epsilon closure of the node which is
+ the first node of the regular expression. */
+ first = dfa->str_tree->first->node_idx;
+ dfa->init_node = first;
+ err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* The back-references which are in initial states can epsilon transit,
+ since in this case all of the subexpressions can be null.
+ Then we add epsilon closures of the nodes which are the next nodes of
+ the back-references. */
+ if (dfa->nbackref > 0)
+ for (i = 0; i < init_nodes.nelem; ++i)
+ {
+ int node_idx = init_nodes.elems[i];
+ re_token_type_t type = dfa->nodes[node_idx].type;
+
+ int clexp_idx;
+ if (type != OP_BACK_REF)
+ continue;
+ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
+ {
+ re_token_t *clexp_node;
+ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
+ if (clexp_node->type == OP_CLOSE_SUBEXP
+ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
+ break;
+ }
+ if (clexp_idx == init_nodes.nelem)
+ continue;
+
+ if (type == OP_BACK_REF)
+ {
+ int dest_idx = dfa->edests[node_idx].elems[0];
+ if (!re_node_set_contains (&init_nodes, dest_idx))
+ {
+ re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+ i = 0;
+ }
+ }
+ }
+
+ /* It must be the first time to invoke acquire_state. */
+ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+ /* We don't check ERR here, since the initial state must not be NULL. */
+ if (BE (dfa->init_state == NULL, 0))
+ return err;
+ if (dfa->init_state->has_constraint)
+ {
+ dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_WORD);
+ dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_NEWLINE);
+ dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
+ &init_nodes,
+ CONTEXT_NEWLINE
+ | CONTEXT_BEGBUF);
+ if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return err;
+ }
+ else
+ dfa->init_state_word = dfa->init_state_nl
+ = dfa->init_state_begbuf = dfa->init_state;
+
+ re_node_set_free (&init_nodes);
+ return REG_NOERROR;
+}
+
+#ifdef RE_ENABLE_I18N
+/* If it is possible to do searching in single byte encoding instead of UTF-8
+ to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
+ DFA nodes where needed. */
+
+static void
+optimize_utf8 (re_dfa_t *dfa)
+{
+ int node, i, mb_chars = 0, has_period = 0;
+
+ for (node = 0; node < dfa->nodes_len; ++node)
+ switch (dfa->nodes[node].type)
+ {
+ case CHARACTER:
+ if (dfa->nodes[node].opr.c >= 0x80)
+ mb_chars = 1;
+ break;
+ case ANCHOR:
+ switch (dfa->nodes[node].opr.idx)
+ {
+ case LINE_FIRST:
+ case LINE_LAST:
+ case BUF_FIRST:
+ case BUF_LAST:
+ break;
+ default:
+ /* Word anchors etc. cannot be handled. */
+ return;
+ }
+ break;
+ case OP_PERIOD:
+ has_period = 1;
+ break;
+ case OP_BACK_REF:
+ case OP_ALT:
+ case END_OF_RE:
+ case OP_DUP_ASTERISK:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ break;
+ case COMPLEX_BRACKET:
+ return;
+ case SIMPLE_BRACKET:
+ /* Just double check. The non-ASCII range starts at 0x80. */
+ assert (0x80 % BITSET_WORD_BITS == 0);
+ for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
+ if (dfa->nodes[node].opr.sbcset[i])
+ return;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mb_chars || has_period)
+ for (node = 0; node < dfa->nodes_len; ++node)
+ {
+ if (dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].opr.c >= 0x80)
+ dfa->nodes[node].mb_partial = 0;
+ else if (dfa->nodes[node].type == OP_PERIOD)
+ dfa->nodes[node].type = OP_UTF8_PERIOD;
+ }
+
+ /* The search can be in single byte locale. */
+ dfa->mb_cur_max = 1;
+ dfa->is_utf8 = 0;
+ dfa->has_mb_node = dfa->nbackref > 0 || has_period;
+}
+#endif
+
+/* Analyze the structure tree, and calculate "first", "next", "edest",
+ "eclosure", and "inveclosure". */
+
+static reg_errcode_t
+analyze (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ reg_errcode_t ret;
+
+ /* Allocate arrays. */
+ dfa->nexts = re_malloc (int, dfa->nodes_alloc);
+ dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
+ dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
+ dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
+ if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
+ || dfa->eclosures == NULL, 0))
+ return REG_ESPACE;
+
+ dfa->subexp_map = re_malloc (int, preg->re_nsub);
+ if (dfa->subexp_map != NULL)
+ {
+ int i;
+ for (i = 0; i < preg->re_nsub; i++)
+ dfa->subexp_map[i] = i;
+ preorder (dfa->str_tree, optimize_subexps, dfa);
+ for (i = 0; i < preg->re_nsub; i++)
+ if (dfa->subexp_map[i] != i)
+ break;
+ if (i == preg->re_nsub)
+ {
+ free (dfa->subexp_map);
+ dfa->subexp_map = NULL;
+ }
+ }
+
+ ret = postorder (dfa->str_tree, lower_subexps, preg);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = postorder (dfa->str_tree, calc_first, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ preorder (dfa->str_tree, calc_next, dfa);
+ ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = calc_eclosure (dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ /* We only need this during the prune_impossible_nodes pass in regexec.c;
+ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
+ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
+ if (BE (dfa->inveclosures == NULL, 0))
+ return REG_ESPACE;
+ ret = calc_inveclosure (dfa);
+ }
+
+ return ret;
+}
+
+/* Our parse trees are very unbalanced, so we cannot use a stack to
+ implement parse tree visits. Instead, we use parent pointers and
+ some hairy code in these two functions. */
+static reg_errcode_t
+postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node, *prev;
+
+ for (node = root; ; )
+ {
+ /* Descend down the tree, preferably to the left (or to the right
+ if that's the only child). */
+ while (node->left || node->right)
+ if (node->left)
+ node = node->left;
+ else
+ node = node->right;
+
+ do
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ if (node->parent == NULL)
+ return REG_NOERROR;
+ prev = node;
+ node = node->parent;
+ }
+ /* Go up while we have a node that is reached from the right. */
+ while (node->right == prev || node->right == NULL);
+ node = node->right;
+ }
+}
+
+static reg_errcode_t
+preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node;
+
+ for (node = root; ; )
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ node = node->left;
+ else
+ {
+ bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ if (!node)
+ return REG_NOERROR;
+ }
+ node = node->right;
+ }
+ }
+}
+
+/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
+ re_search_internal to map the inner one's opr.idx to this one's. Adjust
+ backreferences as well. Requires a preorder visit. */
+static reg_errcode_t
+optimize_subexps (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+
+ if (node->token.type == OP_BACK_REF && dfa->subexp_map)
+ {
+ int idx = node->token.opr.idx;
+ node->token.opr.idx = dfa->subexp_map[idx];
+ dfa->used_bkref_map |= 1 << node->token.opr.idx;
+ }
+
+ else if (node->token.type == SUBEXP
+ && node->left && node->left->token.type == SUBEXP)
+ {
+ int other_idx = node->left->token.opr.idx;
+
+ node->left = node->left->left;
+ if (node->left)
+ node->left->parent = node;
+
+ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
+ if (other_idx < BITSET_WORD_BITS)
+ dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
+ }
+
+ return REG_NOERROR;
+}
+
+/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
+ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
+static reg_errcode_t
+lower_subexps (void *extra, bin_tree_t *node)
+{
+ regex_t *preg = (regex_t *) extra;
+ reg_errcode_t err = REG_NOERROR;
+
+ if (node->left && node->left->token.type == SUBEXP)
+ {
+ node->left = lower_subexp (&err, preg, node->left);
+ if (node->left)
+ node->left->parent = node;
+ }
+ if (node->right && node->right->token.type == SUBEXP)
+ {
+ node->right = lower_subexp (&err, preg, node->right);
+ if (node->right)
+ node->right->parent = node;
+ }
+
+ return err;
+}
+
+static bin_tree_t *
+lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *body = node->left;
+ bin_tree_t *op, *cls, *tree1, *tree;
+
+ if (preg->no_sub
+ /* We do not optimize empty subexpressions, because otherwise we may
+ have bad CONCAT nodes with NULL children. This is obviously not
+ very common, so we do not lose much. An example that triggers
+ this case is the sed "script" /\(\)/x. */
+ && node->left != NULL
+ && (node->token.opr.idx >= BITSET_WORD_BITS
+ || !(dfa->used_bkref_map
+ & ((bitset_word_t) 1 << node->token.opr.idx))))
+ return node->left;
+
+ /* Convert the SUBEXP node to the concatenation of an
+ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
+ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
+ cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
+ tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
+ tree = create_tree (dfa, op, tree1, CONCAT);
+ if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
+ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
+ return tree;
+}
+
+/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
+ nodes. Requires a postorder visit. */
+static reg_errcode_t
+calc_first (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ if (node->token.type == CONCAT)
+ {
+ node->first = node->left->first;
+ node->node_idx = node->left->node_idx;
+ }
+ else
+ {
+ node->first = node;
+ node->node_idx = re_dfa_add_node (dfa, node->token);
+ if (BE (node->node_idx == -1, 0))
+ return REG_ESPACE;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 2: compute NEXT on the tree. Preorder visit. */
+static reg_errcode_t
+calc_next (void *extra, bin_tree_t *node)
+{
+ switch (node->token.type)
+ {
+ case OP_DUP_ASTERISK:
+ node->left->next = node;
+ break;
+ case CONCAT:
+ node->left->next = node->right->first;
+ node->right->next = node->next;
+ break;
+ default:
+ if (node->left)
+ node->left->next = node->next;
+ if (node->right)
+ node->right->next = node->next;
+ break;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
+static reg_errcode_t
+link_nfa_nodes (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ int idx = node->node_idx;
+ reg_errcode_t err = REG_NOERROR;
+
+ switch (node->token.type)
+ {
+ case CONCAT:
+ break;
+
+ case END_OF_RE:
+ assert (node->next == NULL);
+ break;
+
+ case OP_DUP_ASTERISK:
+ case OP_ALT:
+ {
+ int left, right;
+ dfa->has_plural_match = 1;
+ if (node->left != NULL)
+ left = node->left->first->node_idx;
+ else
+ left = node->next->node_idx;
+ if (node->right != NULL)
+ right = node->right->first->node_idx;
+ else
+ right = node->next->node_idx;
+ assert (left > -1);
+ assert (right > -1);
+ err = re_node_set_init_2 (dfa->edests + idx, left, right);
+ }
+ break;
+
+ case ANCHOR:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
+ break;
+
+ case OP_BACK_REF:
+ dfa->nexts[idx] = node->next->node_idx;
+ if (node->token.type == OP_BACK_REF)
+ re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
+ break;
+
+ default:
+ assert (!IS_EPSILON_NODE (node->token.type));
+ dfa->nexts[idx] = node->next->node_idx;
+ break;
+ }
+
+ return err;
+}
+
+/* Duplicate the epsilon closure of the node ROOT_NODE.
+ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
+ to their own constraint. */
+
+static reg_errcode_t
+internal_function
+duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
+ int root_node, unsigned int init_constraint)
+{
+ int org_node, clone_node, ret;
+ unsigned int constraint = init_constraint;
+ for (org_node = top_org_node, clone_node = top_clone_node;;)
+ {
+ int org_dest, clone_dest;
+ if (dfa->nodes[org_node].type == OP_BACK_REF)
+ {
+ /* If the back reference epsilon-transit, its destination must
+ also have the constraint. Then duplicate the epsilon closure
+ of the destination of the back reference, and store it in
+ edests of the back reference. */
+ org_dest = dfa->nexts[org_node];
+ re_node_set_empty (dfa->edests + clone_node);
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else if (dfa->edests[org_node].nelem == 0)
+ {
+ /* In case of the node can't epsilon-transit, don't duplicate the
+ destination and store the original destination as the
+ destination of the node. */
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ break;
+ }
+ else if (dfa->edests[org_node].nelem == 1)
+ {
+ /* In case of the node can epsilon-transit, and it has only one
+ destination. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ if (dfa->nodes[org_node].type == ANCHOR)
+ {
+ /* In case of the node has another constraint, append it. */
+ if (org_node == root_node && clone_node != org_node)
+ {
+ /* ...but if the node is root_node itself, it means the
+ epsilon closure have a loop, then tie it to the
+ destination of the root_node. */
+ ret = re_node_set_insert (dfa->edests + clone_node,
+ org_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ break;
+ }
+ constraint |= dfa->nodes[org_node].opr.ctx_type;
+ }
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else /* dfa->edests[org_node].nelem == 2 */
+ {
+ /* In case of the node can epsilon-transit, and it has two
+ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ /* Search for a duplicated node which satisfies the constraint. */
+ clone_dest = search_duplicated_node (dfa, org_dest, constraint);
+ if (clone_dest == -1)
+ {
+ /* There are no such a duplicated node, create a new one. */
+ reg_errcode_t err;
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ err = duplicate_node_closure (dfa, org_dest, clone_dest,
+ root_node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ {
+ /* There are a duplicated node which satisfy the constraint,
+ use it to avoid infinite loop. */
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+
+ org_dest = dfa->edests[org_node].elems[1];
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ org_node = org_dest;
+ clone_node = clone_dest;
+ }
+ return REG_NOERROR;
+}
+
+/* Search for a node which is duplicated from the node ORG_NODE, and
+ satisfies the constraint CONSTRAINT. */
+
+static int
+search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint)
+{
+ int idx;
+ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
+ {
+ if (org_node == dfa->org_indices[idx]
+ && constraint == dfa->nodes[idx].constraint)
+ return idx; /* Found. */
+ }
+ return -1; /* Not found. */
+}
+
+/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
+ Return the index of the new node, or -1 if insufficient storage is
+ available. */
+
+static int
+duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
+{
+ int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
+ if (BE (dup_idx != -1, 1))
+ {
+ dfa->nodes[dup_idx].constraint = constraint;
+ if (dfa->nodes[org_idx].type == ANCHOR)
+ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
+ dfa->nodes[dup_idx].duplicated = 1;
+
+ /* Store the index of the original node. */
+ dfa->org_indices[dup_idx] = org_idx;
+ }
+ return dup_idx;
+}
+
+static reg_errcode_t
+calc_inveclosure (re_dfa_t *dfa)
+{
+ int src, idx, ret;
+ for (idx = 0; idx < dfa->nodes_len; ++idx)
+ re_node_set_init_empty (dfa->inveclosures + idx);
+
+ for (src = 0; src < dfa->nodes_len; ++src)
+ {
+ int *elems = dfa->eclosures[src].elems;
+ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
+ {
+ ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Calculate "eclosure" for all the node in DFA. */
+
+static reg_errcode_t
+calc_eclosure (re_dfa_t *dfa)
+{
+ int node_idx, incomplete;
+#ifdef DEBUG
+ assert (dfa->nodes_len > 0);
+#endif
+ incomplete = 0;
+ /* For each nodes, calculate epsilon closure. */
+ for (node_idx = 0; ; ++node_idx)
+ {
+ reg_errcode_t err;
+ re_node_set eclosure_elem;
+ if (node_idx == dfa->nodes_len)
+ {
+ if (!incomplete)
+ break;
+ incomplete = 0;
+ node_idx = 0;
+ }
+
+#ifdef DEBUG
+ assert (dfa->eclosures[node_idx].nelem != -1);
+#endif
+
+ /* If we have already calculated, skip it. */
+ if (dfa->eclosures[node_idx].nelem != 0)
+ continue;
+ /* Calculate epsilon closure of `node_idx'. */
+ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (dfa->eclosures[node_idx].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Calculate epsilon closure of NODE. */
+
+static reg_errcode_t
+calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
+{
+ reg_errcode_t err;
+ unsigned int constraint;
+ int i, incomplete;
+ re_node_set eclosure;
+ incomplete = 0;
+ err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* This indicates that we are calculating this node now.
+ We reference this value to avoid infinite loop. */
+ dfa->eclosures[node].nelem = -1;
+
+ constraint = ((dfa->nodes[node].type == ANCHOR)
+ ? dfa->nodes[node].opr.ctx_type : 0);
+ /* If the current node has constraints, duplicate all nodes.
+ Since they must inherit the constraints. */
+ if (constraint
+ && dfa->edests[node].nelem
+ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
+ {
+ err = duplicate_node_closure (dfa, node, node, node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Expand each epsilon destination nodes. */
+ if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ for (i = 0; i < dfa->edests[node].nelem; ++i)
+ {
+ re_node_set eclosure_elem;
+ int edest = dfa->edests[node].elems[i];
+ /* If calculating the epsilon closure of `edest' is in progress,
+ return intermediate result. */
+ if (dfa->eclosures[edest].nelem == -1)
+ {
+ incomplete = 1;
+ continue;
+ }
+ /* If we haven't calculated the epsilon closure of `edest' yet,
+ calculate now. Otherwise use calculated epsilon closure. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ eclosure_elem = dfa->eclosures[edest];
+ /* Merge the epsilon closure of `edest'. */
+ re_node_set_merge (&eclosure, &eclosure_elem);
+ /* If the epsilon closure of `edest' is incomplete,
+ the epsilon closure of this node is also incomplete. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+
+ /* Epsilon closures include itself. */
+ re_node_set_insert (&eclosure, node);
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ return REG_NOERROR;
+}
+
+/* Functions for token which are used in the parser. */
+
+/* Fetch a token from INPUT.
+ We must not use this function inside bracket expressions. */
+
+static void
+internal_function
+fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
+{
+ re_string_skip_bytes (input, peek_token (result, input, syntax));
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function inside bracket expressions. */
+
+static int
+internal_function
+peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+ token->word_char = 0;
+#ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ token->mb_partial = 1;
+ return 1;
+ }
+#endif
+ if (c == '\\')
+ {
+ unsigned char c2;
+ if (re_string_cur_idx (input) + 1 >= re_string_length (input))
+ {
+ token->type = BACK_SLASH;
+ return 1;
+ }
+
+ c2 = re_string_peek_byte_case (input, 1);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (c2) != 0;
+
+ switch (c2)
+ {
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (!(syntax & RE_NO_BK_REFS))
+ {
+ token->type = OP_BACK_REF;
+ token->opr.idx = c2 - '1';
+ }
+ break;
+ case '<':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_FIRST;
+ }
+ break;
+ case '>':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_LAST;
+ }
+ break;
+ case 'b':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_DELIM;
+ }
+ break;
+ case 'B':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = NOT_WORD_DELIM;
+ }
+ break;
+ case 'w':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_WORD;
+ break;
+ case 'W':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTWORD;
+ break;
+ case 's':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_SPACE;
+ break;
+ case 'S':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTSPACE;
+ break;
+ case '`':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_FIRST;
+ }
+ break;
+ case '\'':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_LAST;
+ }
+ break;
+ case '(':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ default:
+ break;
+ }
+ return 2;
+ }
+
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (token->opr.c);
+
+ switch (c)
+ {
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ token->type = OP_ALT;
+ break;
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '*':
+ token->type = OP_DUP_ASTERISK;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '[':
+ token->type = OP_OPEN_BRACKET;
+ break;
+ case '.':
+ token->type = OP_PERIOD;
+ break;
+ case '^':
+ if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
+ re_string_cur_idx (input) != 0)
+ {
+ char prev = re_string_peek_byte (input, -1);
+ if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_FIRST;
+ break;
+ case '$':
+ if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
+ re_string_cur_idx (input) + 1 != re_string_length (input))
+ {
+ re_token_t next;
+ re_string_skip_bytes (input, 1);
+ peek_token (&next, input, syntax);
+ re_string_skip_bytes (input, -1);
+ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_LAST;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function out of bracket expressions. */
+
+static int
+internal_function
+peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ return 1;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
+ && re_string_cur_idx (input) + 1 < re_string_length (input))
+ {
+ /* In this case, '\' escape a character. */
+ unsigned char c2;
+ re_string_skip_bytes (input, 1);
+ c2 = re_string_peek_byte (input, 0);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ return 1;
+ }
+ if (c == '[') /* '[' is a special char in a bracket exps. */
+ {
+ unsigned char c2;
+ int token_len;
+ if (re_string_cur_idx (input) + 1 < re_string_length (input))
+ c2 = re_string_peek_byte (input, 1);
+ else
+ c2 = 0;
+ token->opr.c = c2;
+ token_len = 2;
+ switch (c2)
+ {
+ case '.':
+ token->type = OP_OPEN_COLL_ELEM;
+ break;
+ case '=':
+ token->type = OP_OPEN_EQUIV_CLASS;
+ break;
+ case ':':
+ if (syntax & RE_CHAR_CLASSES)
+ {
+ token->type = OP_OPEN_CHAR_CLASS;
+ break;
+ }
+ /* else fall through. */
+ default:
+ token->type = CHARACTER;
+ token->opr.c = c;
+ token_len = 1;
+ break;
+ }
+ return token_len;
+ }
+ switch (c)
+ {
+ case '-':
+ token->type = OP_CHARSET_RANGE;
+ break;
+ case ']':
+ token->type = OP_CLOSE_BRACKET;
+ break;
+ case '^':
+ token->type = OP_NON_MATCH_LIST;
+ break;
+ default:
+ token->type = CHARACTER;
+ }
+ return 1;
+}
+
+/* Functions for parser. */
+
+/* Entry point of the parser.
+ Parse the regular expression REGEXP and return the structure tree.
+ If an error is occured, ERR is set by error code, and return NULL.
+ This function build the following tree, from regular expression <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> EOR
+
+ CAT means concatenation.
+ EOR means end of regular expression. */
+
+static bin_tree_t *
+parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
+ reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *eor, *root;
+ re_token_t current_token;
+ dfa->syntax = syntax;
+ fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ eor = create_tree (dfa, NULL, NULL, END_OF_RE);
+ if (tree != NULL)
+ root = create_tree (dfa, tree, eor, CONCAT);
+ else
+ root = eor;
+ if (BE (eor == NULL || root == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ return root;
+}
+
+/* This function build the following tree, from regular expression
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ ALT means alternative, which represents the operator `|'. */
+
+static bin_tree_t *
+parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *branch = NULL;
+ tree = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type == OP_ALT)
+ {
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ if (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ branch = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && branch == NULL, 0))
+ return NULL;
+ }
+ else
+ branch = NULL;
+ tree = create_tree (dfa, tree, branch, OP_ALT);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ CAT means concatenation. */
+
+static bin_tree_t *
+parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ bin_tree_t *tree, *exp;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ tree = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ exp = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && exp == NULL, 0))
+ {
+ return NULL;
+ }
+ if (tree != NULL && exp != NULL)
+ {
+ tree = create_tree (dfa, tree, exp, CONCAT);
+ if (tree == NULL)
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else if (tree == NULL)
+ tree = exp;
+ /* Otherwise exp == NULL, we don't need to create new tree. */
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression a*:
+ *
+ |
+ a
+*/
+
+static bin_tree_t *
+parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ switch (token->type)
+ {
+ case CHARACTER:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+ {
+ bin_tree_t *mbc_remain;
+ fetch_token (token, regexp, syntax);
+ mbc_remain = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree, mbc_remain, CONCAT);
+ if (BE (mbc_remain == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ }
+#endif
+ break;
+ case OP_OPEN_SUBEXP:
+ tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_OPEN_BRACKET:
+ tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_BACK_REF:
+ if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
+ {
+ *err = REG_ESUBREG;
+ return NULL;
+ }
+ dfa->used_bkref_map |= 1 << token->opr.idx;
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ ++dfa->nbackref;
+ dfa->has_mb_node = 1;
+ break;
+ case OP_OPEN_DUP_NUM:
+ if (syntax & RE_CONTEXT_INVALID_DUP)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ case OP_DUP_ASTERISK:
+ case OP_DUP_PLUS:
+ case OP_DUP_QUESTION:
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ {
+ fetch_token (token, regexp, syntax);
+ return parse_expression (regexp, preg, token, syntax, nest, err);
+ }
+ /* else fall through */
+ case OP_CLOSE_SUBEXP:
+ if ((token->type == OP_CLOSE_SUBEXP) &&
+ !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
+ {
+ *err = REG_ERPAREN;
+ return NULL;
+ }
+ /* else fall through */
+ case OP_CLOSE_DUP_NUM:
+ /* We treat it as a normal character. */
+
+ /* Then we can these characters as normal characters. */
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be initialized already
+ by peek_token. */
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ break;
+ case ANCHOR:
+ if ((token->opr.ctx_type
+ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
+ && dfa->word_ops_used == 0)
+ init_word_char (dfa);
+ if (token->opr.ctx_type == WORD_DELIM
+ || token->opr.ctx_type == NOT_WORD_DELIM)
+ {
+ bin_tree_t *tree_first, *tree_last;
+ if (token->opr.ctx_type == WORD_DELIM)
+ {
+ token->opr.ctx_type = WORD_FIRST;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = WORD_LAST;
+ }
+ else
+ {
+ token->opr.ctx_type = INSIDE_WORD;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = INSIDE_NOTWORD;
+ }
+ tree_last = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
+ if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else
+ {
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ /* We must return here, since ANCHORs can't be followed
+ by repetition operators.
+ eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ fetch_token (token, regexp, syntax);
+ return tree;
+ case OP_PERIOD:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ if (dfa->mb_cur_max > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+ case OP_NOTWORD:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "alnum",
+ (const unsigned char *) "_",
+ token->type == OP_NOTWORD, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_SPACE:
+ case OP_NOTSPACE:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "space",
+ (const unsigned char *) "",
+ token->type == OP_NOTSPACE, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_ALT:
+ case END_OF_RE:
+ return NULL;
+ case BACK_SLASH:
+ *err = REG_EESCAPE;
+ return NULL;
+ default:
+ /* Must not happen? */
+#ifdef DEBUG
+ assert (0);
+#endif
+ return NULL;
+ }
+ fetch_token (token, regexp, syntax);
+
+ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
+ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
+ {
+ tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ /* In BRE consecutive duplications are not allowed. */
+ if ((syntax & RE_CONTEXT_INVALID_DUP)
+ && (token->type == OP_DUP_ASTERISK
+ || token->type == OP_OPEN_DUP_NUM))
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ }
+
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+static bin_tree_t *
+parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ size_t cur_nsub;
+ cur_nsub = preg->re_nsub++;
+
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+
+ /* The subexpression may be a null string. */
+ if (token->type == OP_CLOSE_SUBEXP)
+ tree = NULL;
+ else
+ {
+ tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
+ if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
+ *err = REG_EPAREN;
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+
+ if (cur_nsub <= '9' - '1')
+ dfa->completed_bkref_map |= 1 << cur_nsub;
+
+ tree = create_tree (dfa, tree, NULL, SUBEXP);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ tree->token.opr.idx = cur_nsub;
+ return tree;
+}
+
+/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
+
+static bin_tree_t *
+parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
+{
+ bin_tree_t *tree = NULL, *old_tree = NULL;
+ int i, start, end, start_idx = re_string_cur_idx (regexp);
+ re_token_t start_token = *token;
+
+ if (token->type == OP_OPEN_DUP_NUM)
+ {
+ end = 0;
+ start = fetch_number (regexp, token, syntax);
+ if (start == -1)
+ {
+ if (token->type == CHARACTER && token->opr.c == ',')
+ start = 0; /* We treat "{,m}" as "{0,m}". */
+ else
+ {
+ *err = REG_BADBR; /* <re>{} is invalid. */
+ return NULL;
+ }
+ }
+ if (BE (start != -2, 1))
+ {
+ /* We treat "{n}" as "{n,n}". */
+ end = ((token->type == OP_CLOSE_DUP_NUM) ? start
+ : ((token->type == CHARACTER && token->opr.c == ',')
+ ? fetch_number (regexp, token, syntax) : -2));
+ }
+ if (BE (start == -2 || end == -2, 0))
+ {
+ /* Invalid sequence. */
+ if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
+ {
+ if (token->type == END_OF_RE)
+ *err = REG_EBRACE;
+ else
+ *err = REG_BADBR;
+
+ return NULL;
+ }
+
+ /* If the syntax bit is set, rollback. */
+ re_string_set_index (regexp, start_idx);
+ *token = start_token;
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be already initialized by
+ peek_token. */
+ return elem;
+ }
+
+ if (BE (end != -1 && start > end, 0))
+ {
+ /* First number greater than second. */
+ *err = REG_BADBR;
+ return NULL;
+ }
+ }
+ else
+ {
+ start = (token->type == OP_DUP_PLUS) ? 1 : 0;
+ end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
+ }
+
+ fetch_token (token, regexp, syntax);
+
+ if (BE (elem == NULL, 0))
+ return NULL;
+ if (BE (start == 0 && end == 0, 0))
+ {
+ postorder (elem, free_tree, NULL);
+ return NULL;
+ }
+
+ /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ if (BE (start > 0, 0))
+ {
+ tree = elem;
+ for (i = 2; i <= start; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (start == end)
+ return tree;
+
+ /* Duplicate ELEM before it is marked optional. */
+ elem = duplicate_tree (elem, dfa);
+ old_tree = tree;
+ }
+ else
+ old_tree = NULL;
+
+ if (elem->token.type == SUBEXP)
+ postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+
+ tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ /* This loop is actually executed only when end != -1,
+ to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
+ already created the start+1-th copy. */
+ for (i = start + 2; i <= end; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ tree = create_tree (dfa, tree, NULL, OP_ALT);
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (old_tree)
+ tree = create_tree (dfa, old_tree, tree, CONCAT);
+
+ return tree;
+
+ parse_dup_op_espace:
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* Size of the names for collating symbol/equivalence_class/character_class.
+ I'm not sure, but maybe enough. */
+#define BRACKET_NAME_BUF_SIZE 32
+
+#ifndef _LIBC
+ /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
+ bracket_elem_t *start_elem, bracket_elem_t *end_elem)
+# else /* not RE_ENABLE_I18N */
+build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem)
+# endif /* not RE_ENABLE_I18N */
+{
+ unsigned int start_ch, end_ch;
+ /* Equivalence Classes and Character Classes can't be a range start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ /* We can handle no multi character collating elements without libc
+ support. */
+ if (BE ((start_elem->type == COLL_SYM
+ && strlen ((char *) start_elem->opr.name) > 1)
+ || (end_elem->type == COLL_SYM
+ && strlen ((char *) end_elem->opr.name) > 1), 0))
+ return REG_ECOLLATE;
+
+# ifdef RE_ENABLE_I18N
+ {
+ wchar_t wc;
+ wint_t start_wc;
+ wint_t end_wc;
+ wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+
+ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
+ ? __btowc (start_ch) : start_elem->opr.wch);
+ end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
+ ? __btowc (end_ch) : end_elem->opr.wch);
+ if (start_wc == WEOF || end_wc == WEOF)
+ return REG_ECOLLATE;
+ cmp_buf[0] = start_wc;
+ cmp_buf[4] = end_wc;
+ if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+ no MBCSET if dfa->mb_cur_max == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ wchar_t *new_array_start, *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ /* Use realloc since mbcset->range_starts and mbcset->range_ends
+ are NULL if *range_alloc == 0. */
+ new_array_start = re_realloc (mbcset->range_starts, wchar_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, wchar_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_wc;
+ mbcset->range_ends[mbcset->nranges++] = end_wc;
+ }
+
+ /* Build the table for single byte characters. */
+ for (wc = 0; wc < SBC_MAX; ++wc)
+ {
+ cmp_buf[2] = wc;
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ bitset_set (sbcset, wc);
+ }
+ }
+# else /* not RE_ENABLE_I18N */
+ {
+ unsigned int ch;
+ start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ if (start_ch > end_ch)
+ return REG_ERANGE;
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ if (start_ch <= ch && ch <= end_ch)
+ bitset_set (sbcset, ch);
+ }
+# endif /* not RE_ENABLE_I18N */
+ return REG_NOERROR;
+}
+#endif /* not _LIBC */
+
+#ifndef _LIBC
+/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument since we may update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
+ int *coll_sym_alloc, const unsigned char *name)
+# else /* not RE_ENABLE_I18N */
+build_collating_symbol (bitset_t sbcset, const unsigned char *name)
+# endif /* not RE_ENABLE_I18N */
+{
+ size_t name_len = strlen ((const char *) name);
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+}
+#endif /* not _LIBC */
+
+/* This function parse bracket expression like "[abc]", "[a-c]",
+ "[[.a-a.]]" etc. */
+
+static bin_tree_t *
+parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err)
+{
+#ifdef _LIBC
+ const unsigned char *collseqmb;
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Seek the collating symbol entry correspondings to NAME.
+ Return the index of the symbol in the SYMB_TABLE. */
+
+ auto inline int32_t
+ __attribute ((always_inline))
+ seek_collating_symbol_entry (name, name_len)
+ const unsigned char *name;
+ size_t name_len;
+ {
+ int32_t hash = elem_hash ((const char *) name, name_len);
+ int32_t elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ int32_t second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ /* Compare the length of the name. */
+ && name_len == extra[symb_table[2 * elem + 1]]
+ /* Compare the name. */
+ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
+ name_len) == 0)
+ {
+ /* Yep, this is the entry. */
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+ return elem;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Look up the collation sequence value of BR_ELEM.
+ Return the value if succeeded, UINT_MAX otherwise. */
+
+ auto inline unsigned int
+ __attribute ((always_inline))
+ lookup_collation_sequence_value (br_elem)
+ bracket_elem_t *br_elem;
+ {
+ if (br_elem->type == SB_CHAR)
+ {
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ return collseqmb[br_elem->opr.ch];
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
+ else if (br_elem->type == MB_CHAR)
+ {
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+ if (nrules != 0)
+ {
+ int32_t elem, idx;
+ elem = seek_collating_symbol_entry (br_elem->opr.name,
+ sym_name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ /* Skip the byte sequence of the collating element. */
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the multibyte collation sequence value. */
+ idx += sizeof (unsigned int);
+ /* Skip the wide char sequence of the collating element. */
+ idx += sizeof (unsigned int) *
+ (1 + *(unsigned int *) (extra + idx));
+ /* Return the collation sequence value. */
+ return *(unsigned int *) (extra + idx);
+ }
+ else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ }
+ else if (sym_name_len == 1)
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ return UINT_MAX;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
+ re_charset_t *mbcset;
+ int *range_alloc;
+ bitset_t sbcset;
+ bracket_elem_t *start_elem, *end_elem;
+ {
+ unsigned int ch;
+ uint32_t start_collseq;
+ uint32_t end_collseq;
+
+ /* Equivalence Classes and Character Classes can't be a range
+ start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ start_collseq = lookup_collation_sequence_value (start_elem);
+ end_collseq = lookup_collation_sequence_value (end_elem);
+ /* Check start/end collation sequence values. */
+ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
+ return REG_ECOLLATE;
+ if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+ if (nrules > 0 || dfa->mb_cur_max > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ uint32_t *new_array_start;
+ uint32_t *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ new_array_start = re_realloc (mbcset->range_starts, uint32_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, uint32_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_collseq;
+ mbcset->range_ends[mbcset->nranges++] = end_collseq;
+ }
+
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ch++)
+ {
+ uint32_t ch_collseq;
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ ch_collseq = collseqmb[ch];
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+ bitset_set (sbcset, ch);
+ }
+ return REG_NOERROR;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument sinse we may update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
+ re_charset_t *mbcset;
+ int *coll_sym_alloc;
+ bitset_t sbcset;
+ const unsigned char *name;
+ {
+ int32_t elem, idx;
+ size_t name_len = strlen ((const char *) name);
+ if (nrules != 0)
+ {
+ elem = seek_collating_symbol_entry (name, name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ }
+ else if (symb_table[2 * elem] == 0 && name_len == 1)
+ {
+ /* No valid character, treat it as a normal
+ character. */
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ else
+ return REG_ECOLLATE;
+
+ /* Got valid collation sequence, add it as a new entry. */
+ /* Check the space of the arrays. */
+ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->ncoll_syms is 0. */
+ int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
+ /* Use realloc since mbcset->coll_syms is NULL
+ if *alloc == 0. */
+ int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
+ new_coll_sym_alloc);
+ if (BE (new_coll_syms == NULL, 0))
+ return REG_ESPACE;
+ mbcset->coll_syms = new_coll_syms;
+ *coll_sym_alloc = new_coll_sym_alloc;
+ }
+ mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
+ return REG_NOERROR;
+ }
+ else
+ {
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ }
+ }
+#endif
+
+ re_token_t br_token;
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
+ int equiv_class_alloc = 0, char_class_alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ int non_match = 0;
+ bin_tree_t *work_tree;
+ int token_len;
+ int first_round = 1;
+#ifdef _LIBC
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules)
+ {
+ /*
+ if (MB_CUR_MAX > 1)
+ */
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+ }
+#endif
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif /* RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_NON_MATCH_LIST)
+ {
+#ifdef RE_ENABLE_I18N
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ non_match = 1;
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set (sbcset, '\0');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ }
+
+ /* We treat the first ']' as a normal character. */
+ if (token->type == OP_CLOSE_BRACKET)
+ token->type = CHARACTER;
+
+ while (1)
+ {
+ bracket_elem_t start_elem, end_elem;
+ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
+ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
+ reg_errcode_t ret;
+ int token_len2 = 0, is_range_exp = 0;
+ re_token_t token2;
+
+ start_elem.opr.name = start_name_buf;
+ ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
+ syntax, first_round);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+ first_round = 0;
+
+ /* Get information about the next token. We need it in any case. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+ /* Do not check for ranges if we know they are not allowed. */
+ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
+ {
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CHARSET_RANGE)
+ {
+ re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
+ token_len2 = peek_token_bracket (&token2, regexp, syntax);
+ if (BE (token2.type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token2.type == OP_CLOSE_BRACKET)
+ {
+ /* We treat the last '-' as a normal character. */
+ re_string_skip_bytes (regexp, -token_len);
+ token->type = CHARACTER;
+ }
+ else
+ is_range_exp = 1;
+ }
+ }
+
+ if (is_range_exp == 1)
+ {
+ end_elem.opr.name = end_name_buf;
+ ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
+ dfa, syntax, 1);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+#ifdef _LIBC
+ *err = build_range_exp (sbcset, mbcset, &range_alloc,
+ &start_elem, &end_elem);
+#else
+# ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+ dfa->mb_cur_max > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+# else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+# endif
+#endif /* RE_ENABLE_I18N */
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ }
+ else
+ {
+ switch (start_elem.type)
+ {
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+#ifdef RE_ENABLE_I18N
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+ {
+ wchar_t *new_mbchars;
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nmbchars is 0. */
+ mbchar_alloc = 2 * mbcset->nmbchars + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
+ mbchar_alloc);
+ if (BE (new_mbchars == NULL, 0))
+ goto parse_bracket_exp_espace;
+ mbcset->mbchars = new_mbchars;
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+#endif /* RE_ENABLE_I18N */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &equiv_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case COLL_SYM:
+ *err = build_collating_symbol (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &coll_sym_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case CHAR_CLASS:
+ *err = build_charclass (regexp->trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &char_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name, syntax);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ }
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CLOSE_BRACKET)
+ break;
+ }
+
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+ || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+ int sbc_idx;
+ /* Build a tree for complex bracket. */
+ dfa->has_mb_node = 1;
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
+ if (sbcset[sbc_idx])
+ break;
+ /* If there are no bits set in sbcset, there is no point
+ of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
+ if (sbc_idx < BITSET_WORDS)
+ {
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+
+ /* Then join them by ALT node. */
+ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ else
+ {
+ re_free (sbcset);
+ work_tree = mbc_tree;
+ }
+ }
+ else
+#endif /* not RE_ENABLE_I18N */
+ {
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ return work_tree;
+
+ parse_bracket_exp_espace:
+ *err = REG_ESPACE;
+ parse_bracket_exp_free_return:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ return NULL;
+}
+
+/* Parse an element in the bracket expression. */
+
+static reg_errcode_t
+parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token, int token_len, re_dfa_t *dfa,
+ reg_syntax_t syntax, int accept_hyphen)
+{
+#ifdef RE_ENABLE_I18N
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+ {
+ elem->type = MB_CHAR;
+ elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+#endif /* RE_ENABLE_I18N */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+ return parse_bracket_symbol (elem, regexp, token);
+ if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
+ {
+ /* A '-' must only appear as anything but a range indicator before
+ the closing bracket. Everything else is an error. */
+ re_token_t token2;
+ (void) peek_token_bracket (&token2, regexp, syntax);
+ if (token2.type != OP_CLOSE_BRACKET)
+ /* The actual error value is not standardized since this whole
+ case is undefined. But ERANGE makes good sense. */
+ return REG_ERANGE;
+ }
+ elem->type = SB_CHAR;
+ elem->opr.ch = token->opr.c;
+ return REG_NOERROR;
+}
+
+/* Parse a bracket symbol in the bracket expression. Bracket symbols are
+ such as [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+static reg_errcode_t
+parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token)
+{
+ unsigned char ch, delim = token->opr.c;
+ int i = 0;
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ for (;; ++i)
+ {
+ if (i >= BRACKET_NAME_BUF_SIZE)
+ return REG_EBRACK;
+ if (token->type == OP_OPEN_CHAR_CLASS)
+ ch = re_string_fetch_byte_case (regexp);
+ else
+ ch = re_string_fetch_byte (regexp);
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
+ break;
+ elem->opr.name[i] = ch;
+ }
+ re_string_skip_bytes (regexp, 1);
+ elem->opr.name[i] = '\0';
+ switch (token->type)
+ {
+ case OP_OPEN_COLL_ELEM:
+ elem->type = COLL_SYM;
+ break;
+ case OP_OPEN_EQUIV_CLASS:
+ elem->type = EQUIV_CLASS;
+ break;
+ case OP_OPEN_CHAR_CLASS:
+ elem->type = CHAR_CLASS;
+ break;
+ default:
+ break;
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the equivalence class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
+ int *equiv_class_alloc, const unsigned char *name)
+#else /* not RE_ENABLE_I18N */
+build_equiv_class (bitset_t sbcset, const unsigned char *name)
+#endif /* not RE_ENABLE_I18N */
+{
+#ifdef _LIBC
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra, *cp;
+ unsigned char char_buf[2];
+ int32_t idx1, idx2;
+ unsigned int ch;
+ size_t len;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+ /* Calculate the index for equivalence class. */
+ cp = name;
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ idx1 = findidx (&cp);
+ if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
+ /* This isn't a valid character. */
+ return REG_ECOLLATE;
+
+ /* Build single byte matcing table for this equivalence class. */
+ char_buf[1] = (unsigned char) '\0';
+ len = weights[idx1];
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ {
+ char_buf[0] = ch;
+ cp = char_buf;
+ idx2 = findidx (&cp);
+/*
+ idx2 = table[ch];
+*/
+ if (idx2 == 0)
+ /* This isn't a valid character. */
+ continue;
+ if (len == weights[idx2])
+ {
+ int cnt = 0;
+ while (cnt <= len &&
+ weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt])
+ ++cnt;
+
+ if (cnt > len)
+ bitset_set (sbcset, ch);
+ }
+ }
+ /* Check whether the array has enough space. */
+ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nequiv_classes is 0. */
+ int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
+ /* Use realloc since the array is NULL if *alloc == 0. */
+ int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
+ int32_t,
+ new_equiv_class_alloc);
+ if (BE (new_equiv_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->equiv_classes = new_equiv_classes;
+ *equiv_class_alloc = new_equiv_class_alloc;
+ }
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+#endif /* _LIBC */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, *name);
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the character class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ re_charset_t *mbcset, int *char_class_alloc,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#else /* not RE_ENABLE_I18N */
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#endif /* not RE_ENABLE_I18N */
+{
+ int i;
+ const char *name = (const char *) class_name;
+
+ /* In case of REG_ICASE "upper" and "lower" match the both of
+ upper and lower cases. */
+ if ((syntax & RE_ICASE)
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+#ifdef RE_ENABLE_I18N
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nchar_classes is 0. */
+ int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
+ new_char_class_alloc);
+ if (BE (new_char_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->char_classes = new_char_classes;
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+#endif /* RE_ENABLE_I18N */
+
+#define BUILD_CHARCLASS_LOOP(ctype_func) \
+ do { \
+ if (BE (trans != NULL, 0)) \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, trans[i]); \
+ } \
+ else \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, i); \
+ } \
+ } while (0)
+
+ if (strcmp (name, "alnum") == 0)
+ BUILD_CHARCLASS_LOOP (isalnum);
+ else if (strcmp (name, "cntrl") == 0)
+ BUILD_CHARCLASS_LOOP (iscntrl);
+ else if (strcmp (name, "lower") == 0)
+ BUILD_CHARCLASS_LOOP (islower);
+ else if (strcmp (name, "space") == 0)
+ BUILD_CHARCLASS_LOOP (isspace);
+ else if (strcmp (name, "alpha") == 0)
+ BUILD_CHARCLASS_LOOP (isalpha);
+ else if (strcmp (name, "digit") == 0)
+ BUILD_CHARCLASS_LOOP (isdigit);
+ else if (strcmp (name, "print") == 0)
+ BUILD_CHARCLASS_LOOP (isprint);
+ else if (strcmp (name, "upper") == 0)
+ BUILD_CHARCLASS_LOOP (isupper);
+ else if (strcmp (name, "blank") == 0)
+ BUILD_CHARCLASS_LOOP (isblank);
+ else if (strcmp (name, "graph") == 0)
+ BUILD_CHARCLASS_LOOP (isgraph);
+ else if (strcmp (name, "punct") == 0)
+ BUILD_CHARCLASS_LOOP (ispunct);
+ else if (strcmp (name, "xdigit") == 0)
+ BUILD_CHARCLASS_LOOP (isxdigit);
+ else
+ return REG_ECTYPE;
+
+ return REG_NOERROR;
+}
+
+static bin_tree_t *
+build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra, int non_match,
+ reg_errcode_t *err)
+{
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ reg_errcode_t ret;
+ re_token_t br_token;
+ bin_tree_t *tree;
+
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else /* not RE_ENABLE_I18N */
+ if (BE (sbcset == NULL, 0))
+#endif /* not RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ if (non_match)
+ {
+#ifdef RE_ENABLE_I18N
+ /*
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set(cset->sbcset, '\0');
+ */
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ }
+
+ /* We don't care the syntax in this case. */
+ ret = build_charclass (trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &alloc,
+#endif /* RE_ENABLE_I18N */
+ class_name, 0);
+
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = ret;
+ return NULL;
+ }
+ /* \w match '_' also. */
+ for (; *extra; extra++)
+ bitset_set (sbcset, *extra);
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+#endif
+
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (tree == NULL, 0))
+ goto build_word_op_espace;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ dfa->has_mb_node = 1;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto build_word_op_espace;
+ /* Then join them by ALT node. */
+ tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
+ if (BE (mbc_tree != NULL, 1))
+ return tree;
+ }
+ else
+ {
+ free_charset (mbcset);
+ return tree;
+ }
+#else /* not RE_ENABLE_I18N */
+ return tree;
+#endif /* not RE_ENABLE_I18N */
+
+ build_word_op_espace:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* This is intended for the expressions like "a{1,3}".
+ Fetch a number from `input', and return the number.
+ Return -1, if the number field is empty like "{,1}".
+ Return -2, If an error is occured. */
+
+static int
+fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
+{
+ int num = -1;
+ unsigned char c;
+ while (1)
+ {
+ fetch_token (token, input, syntax);
+ c = token->opr.c;
+ if (BE (token->type == END_OF_RE, 0))
+ return -2;
+ if (token->type == OP_CLOSE_DUP_NUM || c == ',')
+ break;
+ num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
+ ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
+ num = (num > RE_DUP_MAX) ? -2 : num;
+ }
+ return num;
+}
+
+#ifdef RE_ENABLE_I18N
+static void
+free_charset (re_charset_t *cset)
+{
+ re_free (cset->mbchars);
+# ifdef _LIBC
+ re_free (cset->coll_syms);
+ re_free (cset->equiv_classes);
+ re_free (cset->range_starts);
+ re_free (cset->range_ends);
+# endif
+ re_free (cset->char_classes);
+ re_free (cset);
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Functions for binary tree operation. */
+
+/* Create a tree node. */
+
+static bin_tree_t *
+create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type)
+{
+ re_token_t t;
+ t.type = type;
+ return create_token_tree (dfa, left, right, &t);
+}
+
+static bin_tree_t *
+create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token)
+{
+ bin_tree_t *tree;
+ if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
+ {
+ bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
+
+ if (storage == NULL)
+ return NULL;
+ storage->next = dfa->str_tree_storage;
+ dfa->str_tree_storage = storage;
+ dfa->str_tree_storage_idx = 0;
+ }
+ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
+
+ tree->parent = NULL;
+ tree->left = left;
+ tree->right = right;
+ tree->token = *token;
+ tree->token.duplicated = 0;
+ tree->token.opt_subexp = 0;
+ tree->first = NULL;
+ tree->next = NULL;
+ tree->node_idx = -1;
+
+ if (left != NULL)
+ left->parent = tree;
+ if (right != NULL)
+ right->parent = tree;
+ return tree;
+}
+
+/* Mark the tree SRC as an optional subexpression.
+ To be called from preorder or postorder. */
+
+static reg_errcode_t
+mark_opt_subexp (void *extra, bin_tree_t *node)
+{
+ int idx = (int) (long) extra;
+ if (node->token.type == SUBEXP && node->token.opr.idx == idx)
+ node->token.opt_subexp = 1;
+
+ return REG_NOERROR;
+}
+
+/* Free the allocated memory inside NODE. */
+
+static void
+free_token (re_token_t *node)
+{
+#ifdef RE_ENABLE_I18N
+ if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
+ free_charset (node->opr.mbcset);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
+ re_free (node->opr.sbcset);
+}
+
+/* Worker function for tree walking. Free the allocated memory inside NODE
+ and its children. */
+
+static reg_errcode_t
+free_tree (void *extra, bin_tree_t *node)
+{
+ free_token (&node->token);
+ return REG_NOERROR;
+}
+
+
+/* Duplicate the node SRC, and return new node. This is a preorder
+ visit similar to the one implemented by the generic visitor, but
+ we need more infrastructure to maintain two parallel trees --- so,
+ it's easier to duplicate. */
+
+static bin_tree_t *
+duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
+{
+ const bin_tree_t *node;
+ bin_tree_t *dup_root;
+ bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
+
+ for (node = root; ; )
+ {
+ /* Create a new tree and link it back to the current parent. */
+ *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
+ if (*p_new == NULL)
+ return NULL;
+ (*p_new)->parent = dup_node;
+ (*p_new)->token.duplicated = 1;
+ dup_node = *p_new;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ {
+ node = node->left;
+ p_new = &dup_node->left;
+ }
+ else
+ {
+ const bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ dup_node = dup_node->parent;
+ if (!node)
+ return dup_root;
+ }
+ node = node->right;
+ p_new = &dup_node->right;
+ }
+ }
+}
diff --git a/libc/posix/regex.c b/libc/posix/regex.c
new file mode 100644
index 000000000..d2d4f28e0
--- /dev/null
+++ b/libc/posix/regex.c
@@ -0,0 +1,74 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Make sure noone compiles this code with a C++ compiler. */
+#ifdef __cplusplus
+# error "This is C code, use a C compiler"
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean. */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+ __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+ __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+ __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+ __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+ __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+# include "../locale/localeinfo.h"
+#endif
+
+/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
+ GNU regex allows. Include it before <regex.h>, which correctly
+ #undefs RE_DUP_MAX and sets it to the right value. */
+#include <limits.h>
+
+#include <regex.h>
+#include "regex_internal.h"
+
+#include "regex_internal.c"
+#include "regcomp.c"
+#include "regexec.c"
+
+/* Binary backward compatibility. */
+#if _LIBC
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
+link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
+int re_max_failures = 2000;
+# endif
+#endif
diff --git a/libc/posix/regex.h b/libc/posix/regex.h
new file mode 100644
index 000000000..807c404ec
--- /dev/null
+++ b/libc/posix/regex.h
@@ -0,0 +1,556 @@
+/* Definitions for data structures and routines for the regular
+ expression library.
+ Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+#include <sys/types.h>
+
+/* Allow the use in C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+
+/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
+ for ^, because it is difficult to scan the regex backwards to find
+ whether ^ should be special. */
+#define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
+
+/* If this bit is set, then \{ cannot be first in an bre or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
+
+/* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
+ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \
+ | RE_CONTEXT_INVALID_OPS ))
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
+ | RE_INTERVALS | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
+ | RE_INVALID_INTERVAL_ORD)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
+ removed and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+/* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+#define REG_STARTEND (1 << 2)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+ REG_ENOSYS = -1, /* This will never happen for this implementation. */
+#endif
+
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Inalid collating element. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE unsigned char *
+#endif
+
+struct re_pattern_buffer
+{
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are sometimes used as
+ array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long int allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long int used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses the
+ fastmap, if there is one, to skip over impossible starting points
+ for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation is
+ applied to a pattern when it is compiled and to a string when it
+ is matched. */
+ RE_TRANSLATE_TYPE translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see whether or
+ not we should use the fastmap, so we don't set this absolutely
+ perfectly; see `re_compile_fastmap' (the `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the beginning
+ of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern (const char *__pattern, size_t __length,
+ struct re_pattern_buffer *__buffer);
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search (struct re_pattern_buffer *__buffer, const char *__string,
+ int __length, int __start, int __range,
+ struct re_registers *__regs);
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, int __length1,
+ const char *__string2, int __length2, int __start,
+ int __range, struct re_registers *__regs, int __stop);
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match (struct re_pattern_buffer *__buffer, const char *__string,
+ int __length, int __start, struct re_registers *__regs);
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, int __length1,
+ const char *__string2, int __length2, int __start,
+ struct re_registers *__regs, int __stop);
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers (struct re_pattern_buffer *__buffer,
+ struct re_registers *__regs,
+ unsigned int __num_regs,
+ regoff_t *__starts, regoff_t *__ends);
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility. */
+extern char *re_comp (const char *);
+extern int re_exec (const char *);
+# endif
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict". */
+#ifndef __restrict
+# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
+# if defined restrict || 199901L <= __STDC_VERSION__
+# define __restrict restrict
+# else
+# define __restrict
+# endif
+# endif
+#endif
+/* gcc 3.1 and up support the [restrict] syntax. */
+#ifndef __restrict_arr
+# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
+ && !defined __GNUG__
+# define __restrict_arr __restrict
+# else
+# define __restrict_arr
+# endif
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp (regex_t *__restrict __preg,
+ const char *__restrict __pattern,
+ int __cflags);
+
+extern int regexec (const regex_t *__restrict __preg,
+ const char *__restrict __string, size_t __nmatch,
+ regmatch_t __pmatch[__restrict_arr],
+ int __eflags);
+
+extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
+ char *__restrict __errbuf, size_t __errbuf_size);
+
+extern void regfree (regex_t *__preg);
+
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
diff --git a/libc/posix/regex_internal.c b/libc/posix/regex_internal.c
new file mode 100644
index 000000000..ac312db0c
--- /dev/null
+++ b/libc/posix/regex_internal.c
@@ -0,0 +1,1651 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static void re_string_construct_common (const char *str, int len,
+ re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa) internal_function;
+static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int hash) internal_function;
+static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context,
+ unsigned int hash) internal_function;
+
+/* Functions for string operation. */
+
+/* This function allocate the buffers. It is necessary to call
+ re_string_reconstruct before using the object. */
+
+static reg_errcode_t
+internal_function
+re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ int init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+ if (init_len < dfa->mb_cur_max)
+ init_len = dfa->mb_cur_max;
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ ret = re_string_realloc_buffers (pstr, init_buf_len);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+ pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+}
+
+/* This function allocate the buffers, and initialize them. */
+
+static reg_errcode_t
+internal_function
+re_string_construct (re_string_t *pstr, const char *str, int len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ memset (pstr, '\0', sizeof (re_string_t));
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ if (len > 0)
+ {
+ ret = re_string_realloc_buffers (pstr, len + 1);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+
+ if (icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+ if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (trans != NULL)
+ re_string_translate_buffer (pstr);
+ else
+ {
+ pstr->valid_len = pstr->bufs_len;
+ pstr->valid_raw_len = pstr->bufs_len;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions for re_string_allocate, and re_string_construct. */
+
+static reg_errcode_t
+internal_function
+re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
+{
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
+ if (BE (new_wcs == NULL, 0))
+ return REG_ESPACE;
+ pstr->wcs = new_wcs;
+ if (pstr->offsets != NULL)
+ {
+ int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len);
+ if (BE (new_offsets == NULL, 0))
+ return REG_ESPACE;
+ pstr->offsets = new_offsets;
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ {
+ unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
+ new_buf_len);
+ if (BE (new_mbs == NULL, 0))
+ return REG_ESPACE;
+ pstr->mbs = new_mbs;
+ }
+ pstr->bufs_len = new_buf_len;
+ return REG_NOERROR;
+}
+
+
+static void
+internal_function
+re_string_construct_common (const char *str, int len, re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa)
+{
+ pstr->raw_mbs = (const unsigned char *) str;
+ pstr->len = len;
+ pstr->raw_len = len;
+ pstr->trans = trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+ pstr->mb_cur_max = dfa->mb_cur_max;
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+ pstr->raw_stop = pstr->stop;
+}
+
+#ifdef RE_ENABLE_I18N
+
+/* Build wide character buffer PSTR->WCS.
+ If the byte sequence of the string are:
+ <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
+ Then wide character buffer will be:
+ <wc1> , WEOF , <wc2> , WEOF , <wc3>
+ We use WEOF for padding, they indicate that the position isn't
+ a first byte of a multibyte character.
+
+ Note that this function assumes PSTR->VALID_LEN elements are already
+ built and starts from PSTR->VALID_LEN. */
+
+static void
+internal_function
+build_wcs_buffer (re_string_t *pstr)
+{
+#ifdef _LIBC
+ unsigned char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ unsigned char buf[64];
+#endif
+ mbstate_t prev_st;
+ int byte_idx, end_idx, remain_len;
+ size_t mbclen;
+
+ /* Build the buffers from pstr->valid_len to either pstr->len or
+ pstr->bufs_len. */
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+ for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ /* Apply the translation if we need. */
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ if (BE (pstr->trans != NULL, 0))
+ wc = pstr->trans[wc];
+ pstr->cur_state = prev_st;
+ }
+
+ /* Write wide character and padding. */
+ pstr->wcs[byte_idx++] = wc;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+}
+
+/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
+ but for REG_ICASE. */
+
+static reg_errcode_t
+internal_function
+build_wcs_upper_buffer (re_string_t *pstr)
+{
+ mbstate_t prev_st;
+ int src_idx, byte_idx, end_idx, remain_len;
+ size_t mbclen;
+#ifdef _LIBC
+ char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ char buf[64];
+#endif
+
+ byte_idx = pstr->valid_len;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ /* The following optimization assumes that ASCII characters can be
+ mapped to wide characters with a simple cast. */
+ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
+ {
+ while (byte_idx < end_idx)
+ {
+ wchar_t wc;
+
+ if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
+ && mbsinit (&pstr->cur_state))
+ {
+ /* In case of a singlebyte character. */
+ pstr->mbs[byte_idx]
+ = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
+ /* The next step uses the assumption that wchar_t is encoded
+ ASCII-safe: all ASCII values can be converted like this. */
+ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
+ ++byte_idx;
+ continue;
+ }
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc,
+ ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ + byte_idx), remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb (buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else
+ {
+ src_idx = byte_idx;
+ goto offsets_needed;
+ }
+ }
+ else
+ memcpy (pstr->mbs + byte_idx,
+ pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ pstr->mbs[byte_idx] = ch;
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+ return REG_NOERROR;
+ }
+ else
+ for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+ offsets_needed:
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else if (mbcdlen != (size_t) -1)
+ {
+ size_t i;
+
+ if (byte_idx + mbcdlen > pstr->bufs_len)
+ {
+ pstr->cur_state = prev_st;
+ break;
+ }
+
+ if (pstr->offsets == NULL)
+ {
+ pstr->offsets = re_malloc (int, pstr->bufs_len);
+
+ if (pstr->offsets == NULL)
+ return REG_ESPACE;
+ }
+ if (!pstr->offsets_needed)
+ {
+ for (i = 0; i < (size_t) byte_idx; ++i)
+ pstr->offsets[i] = i;
+ pstr->offsets_needed = 1;
+ }
+
+ memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
+ pstr->wcs[byte_idx] = wcu;
+ pstr->offsets[byte_idx] = src_idx;
+ for (i = 1; i < mbcdlen; ++i)
+ {
+ pstr->offsets[byte_idx + i]
+ = src_idx + (i < mbclen ? i : mbclen - 1);
+ pstr->wcs[byte_idx + i] = WEOF;
+ }
+ pstr->len += mbcdlen - mbclen;
+ if (pstr->raw_stop > src_idx)
+ pstr->stop += mbcdlen - mbclen;
+ end_idx = (pstr->bufs_len > pstr->len)
+ ? pstr->len : pstr->bufs_len;
+ byte_idx += mbcdlen;
+ src_idx += mbclen;
+ continue;
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ {
+ size_t i;
+ for (i = 0; i < mbclen; ++i)
+ pstr->offsets[byte_idx + i] = src_idx + i;
+ }
+ src_idx += mbclen;
+
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
+
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans [ch];
+ pstr->mbs[byte_idx] = ch;
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ pstr->offsets[byte_idx] = src_idx;
+ ++src_idx;
+
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = src_idx;
+ return REG_NOERROR;
+}
+
+/* Skip characters until the index becomes greater than NEW_RAW_IDX.
+ Return the index. */
+
+static int
+internal_function
+re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc)
+{
+ mbstate_t prev_st;
+ int rawbuf_idx;
+ size_t mbclen;
+ wchar_t wc = WEOF;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+ rawbuf_idx < new_raw_idx;)
+ {
+ int remain_len;
+ remain_len = pstr->len - rawbuf_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a single byte character. */
+ if (mbclen == 0 || remain_len == 0)
+ wc = L'\0';
+ else
+ wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+ /* Then proceed the next character. */
+ rawbuf_idx += mbclen;
+ }
+ *last_wc = (wint_t) wc;
+ return rawbuf_idx;
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Build the buffer PSTR->MBS, and apply the translation if we need.
+ This function is used in case of REG_ICASE. */
+
+static void
+internal_function
+build_upper_buffer (re_string_t *pstr)
+{
+ int char_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans[ch];
+ if (islower (ch))
+ pstr->mbs[char_idx] = toupper (ch);
+ else
+ pstr->mbs[char_idx] = ch;
+ }
+ pstr->valid_len = char_idx;
+ pstr->valid_raw_len = char_idx;
+}
+
+/* Apply TRANS to the buffer in PSTR. */
+
+static void
+internal_function
+re_string_translate_buffer (re_string_t *pstr)
+{
+ int buf_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
+ pstr->mbs[buf_idx] = pstr->trans[ch];
+ }
+
+ pstr->valid_len = buf_idx;
+ pstr->valid_raw_len = buf_idx;
+}
+
+/* This function re-construct the buffers.
+ Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+ convert to upper case in case of REG_ICASE, apply translation. */
+
+static reg_errcode_t
+internal_function
+re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
+{
+ int offset = idx - pstr->raw_mbs_idx;
+ if (BE (offset < 0, 0))
+ {
+ /* Reset buffer. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+#endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+ pstr->stop = pstr->raw_stop;
+ pstr->valid_len = 0;
+ pstr->raw_mbs_idx = 0;
+ pstr->valid_raw_len = 0;
+ pstr->offsets_needed = 0;
+ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
+ if (!pstr->mbs_allocated)
+ pstr->mbs = (unsigned char *) pstr->raw_mbs;
+ offset = idx;
+ }
+
+ if (BE (offset != 0, 1))
+ {
+ /* Are the characters which are already checked remain? */
+ if (BE (offset < pstr->valid_raw_len, 1)
+#ifdef RE_ENABLE_I18N
+ /* Handling this would enlarge the code too much.
+ Accept a slowdown in that case. */
+ && pstr->offsets_needed == 0
+#endif
+ )
+ {
+ /* Yes, move them to the front of the buffer. */
+ pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags);
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ memmove (pstr->mbs, pstr->mbs + offset,
+ pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+#if DEBUG
+ assert (pstr->valid_len > 0);
+#endif
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ }
+#endif
+ pstr->valid_len = 0;
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+
+ if (pstr->is_utf8)
+ {
+ const unsigned char *raw, *p, *q, *end;
+
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+ end = raw + (offset - pstr->mb_cur_max);
+ p = raw + offset - 1;
+#ifdef _LIBC
+ /* We know the wchar_t encoding is UCS4, so for the simple
+ case, ASCII characters, skip the conversion step. */
+ if (isascii (*p) && BE (pstr->trans == NULL, 1))
+ {
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+ pstr->valid_len = 0;
+ wc = (wchar_t) *p;
+ }
+ else
+#endif
+ for (; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+ mbstate_t cur_state;
+ wchar_t wc2;
+ int mlen = raw + pstr->len - p;
+ unsigned char buf[6];
+ size_t mbclen;
+
+ q = p;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i = mlen < 6 ? mlen : 6;
+ while (--i >= 0)
+ buf[i] = pstr->trans[p[i]];
+ q = buf;
+ }
+ /* XXX Don't use mbrtowc, we know which conversion
+ to use (UTF-8 -> UCS4). */
+ memset (&cur_state, 0, sizeof (cur_state));
+ mbclen = mbrtowc (&wc2, (const char *) p, mlen,
+ &cur_state);
+ if (raw + offset - p <= mbclen
+ && mbclen < (size_t) -2)
+ {
+ memset (&pstr->cur_state, '\0',
+ sizeof (mbstate_t));
+ pstr->valid_len = mbclen - (raw + offset - p);
+ wc = wc2;
+ }
+ break;
+ }
+ }
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (wc == WEOF)
+ pstr->tip_context
+ = re_string_context_at (pstr, pstr->valid_raw_len - 1, eflags);
+ else
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
+ ? CONTEXT_WORD
+ : ((IS_WIDE_NEWLINE (wc)
+ && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+ pstr->wcs[wcs_idx] = WEOF;
+ if (pstr->mbs_allocated)
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
+ pstr->valid_raw_len = 0;
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
+ ? CONTEXT_WORD
+ : ((IS_NEWLINE (c) && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ }
+ if (!BE (pstr->mbs_allocated, 0))
+ pstr->mbs += offset;
+ }
+ pstr->raw_mbs_idx = idx;
+ pstr->len -= offset;
+ pstr->stop -= offset;
+
+ /* Then build the buffers. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ if (pstr->icase)
+ {
+ reg_errcode_t ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+ build_wcs_buffer (pstr);
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ {
+ if (pstr->icase)
+ build_upper_buffer (pstr);
+ else if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ else
+ pstr->valid_len = pstr->len;
+
+ pstr->cur_idx = 0;
+ return REG_NOERROR;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_peek_byte_case (const re_string_t *pstr, int idx)
+{
+ int ch, off;
+
+ /* Handle the common (easiest) cases first. */
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_peek_byte (pstr, idx);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ off = pstr->cur_idx + idx;
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ off = pstr->offsets[off];
+#endif
+
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
+ this function returns CAPITAL LETTER I instead of first byte of
+ DOTLESS SMALL LETTER I. The latter would confuse the parser,
+ since peek_byte_case doesn't advance cur_idx in any way. */
+ if (pstr->offsets_needed && !isascii (ch))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ return ch;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_fetch_byte_case (re_string_t *pstr)
+{
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_fetch_byte (pstr);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ {
+ int off, ch;
+
+ /* For tr_TR.UTF-8 [[:islower:]] there is
+ [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
+ in that case the whole multi-byte character and return
+ the original letter. On the other side, with
+ [[: DOTLESS SMALL LETTER I return [[:I, as doing
+ anything else would complicate things too much. */
+
+ if (!re_string_first_byte (pstr, pstr->cur_idx))
+ return re_string_fetch_byte (pstr);
+
+ off = pstr->offsets[pstr->cur_idx];
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+ if (! isascii (ch))
+ return re_string_fetch_byte (pstr);
+
+ re_string_skip_bytes (pstr,
+ re_string_char_size_at (pstr, pstr->cur_idx));
+ return ch;
+ }
+#endif
+
+ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
+}
+
+static void
+internal_function
+re_string_destruct (re_string_t *pstr)
+{
+#ifdef RE_ENABLE_I18N
+ re_free (pstr->wcs);
+ re_free (pstr->offsets);
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ re_free (pstr->mbs);
+}
+
+/* Return the context at IDX in INPUT. */
+
+static unsigned int
+internal_function
+re_string_context_at (const re_string_t *input, int idx, int eflags)
+{
+ int c;
+ if (BE (idx < 0, 0))
+ /* In this case, we use the value stored in input->tip_context,
+ since we can't know the character in input->mbs[-1] here. */
+ return input->tip_context;
+ if (BE (idx == input->len, 0))
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+ while(input->wcs[wc_idx] == WEOF)
+ {
+#ifdef DEBUG
+ /* It must not happen. */
+ assert (wc_idx >= 0);
+#endif
+ --wc_idx;
+ if (wc_idx < 0)
+ return input->tip_context;
+ }
+ wc = input->wcs[wc_idx];
+ if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
+ return CONTEXT_WORD;
+ return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
+ ? CONTEXT_NEWLINE : 0);
+ }
+ else
+#endif
+ {
+ c = re_string_byte_at (input, idx);
+ if (bitset_contain (input->word_char, c))
+ return CONTEXT_WORD;
+ return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
+ }
+}
+
+/* Functions for set operation. */
+
+static reg_errcode_t
+internal_function
+re_node_set_alloc (re_node_set *set, int size)
+{
+ set->alloc = size;
+ set->nelem = 0;
+ set->elems = re_malloc (int, size);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_1 (re_node_set *set, int elem)
+{
+ set->alloc = 1;
+ set->nelem = 1;
+ set->elems = re_malloc (int, 1);
+ if (BE (set->elems == NULL, 0))
+ {
+ set->alloc = set->nelem = 0;
+ return REG_ESPACE;
+ }
+ set->elems[0] = elem;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_2 (re_node_set *set, int elem1, int elem2)
+{
+ set->alloc = 2;
+ set->elems = re_malloc (int, 2);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ if (elem1 == elem2)
+ {
+ set->nelem = 1;
+ set->elems[0] = elem1;
+ }
+ else
+ {
+ set->nelem = 2;
+ if (elem1 < elem2)
+ {
+ set->elems[0] = elem1;
+ set->elems[1] = elem2;
+ }
+ else
+ {
+ set->elems[0] = elem2;
+ set->elems[1] = elem1;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
+{
+ dest->nelem = src->nelem;
+ if (src->nelem > 0)
+ {
+ dest->alloc = dest->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ {
+ dest->alloc = dest->nelem = 0;
+ return REG_ESPACE;
+ }
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ }
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+}
+
+/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded.
+ Note: We assume dest->elems is NULL, when dest->alloc is 0. */
+
+static reg_errcode_t
+internal_function
+re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, is, id, delta, sbase;
+ if (src1->nelem == 0 || src2->nelem == 0)
+ return REG_NOERROR;
+
+ /* We need dest->nelem + 2 * elems_in_intersection; this is a
+ conservative estimate. */
+ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
+ {
+ int new_alloc = src1->nelem + src2->nelem + dest->alloc;
+ int *new_elems = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_elems == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_elems;
+ dest->alloc = new_alloc;
+ }
+
+ /* Find the items in the intersection of SRC1 and SRC2, and copy
+ into the top of DEST those that are not already in DEST itself. */
+ sbase = dest->nelem + src1->nelem + src2->nelem;
+ i1 = src1->nelem - 1;
+ i2 = src2->nelem - 1;
+ id = dest->nelem - 1;
+ for (;;)
+ {
+ if (src1->elems[i1] == src2->elems[i2])
+ {
+ /* Try to find the item in DEST. Maybe we could binary search? */
+ while (id >= 0 && dest->elems[id] > src1->elems[i1])
+ --id;
+
+ if (id < 0 || dest->elems[id] != src1->elems[i1])
+ dest->elems[--sbase] = src1->elems[i1];
+
+ if (--i1 < 0 || --i2 < 0)
+ break;
+ }
+
+ /* Lower the highest of the two items. */
+ else if (src1->elems[i1] < src2->elems[i2])
+ {
+ if (--i2 < 0)
+ break;
+ }
+ else
+ {
+ if (--i1 < 0)
+ break;
+ }
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + src1->nelem + src2->nelem - 1;
+ delta = is - sbase + 1;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place; this is more or
+ less the same loop that is in re_node_set_merge. */
+ dest->nelem += delta;
+ if (delta > 0 && id >= 0)
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ break;
+ }
+ }
+
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
+
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets SRC1 and SRC2. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, id;
+ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
+ {
+ dest->alloc = src1->nelem + src2->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ return REG_ESPACE;
+ }
+ else
+ {
+ if (src1 != NULL && src1->nelem > 0)
+ return re_node_set_init_copy (dest, src1);
+ else if (src2 != NULL && src2->nelem > 0)
+ return re_node_set_init_copy (dest, src2);
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+ }
+ for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
+ {
+ if (src1->elems[i1] > src2->elems[i2])
+ {
+ dest->elems[id++] = src2->elems[i2++];
+ continue;
+ }
+ if (src1->elems[i1] == src2->elems[i2])
+ ++i2;
+ dest->elems[id++] = src1->elems[i1++];
+ }
+ if (i1 < src1->nelem)
+ {
+ memcpy (dest->elems + id, src1->elems + i1,
+ (src1->nelem - i1) * sizeof (int));
+ id += src1->nelem - i1;
+ }
+ else if (i2 < src2->nelem)
+ {
+ memcpy (dest->elems + id, src2->elems + i2,
+ (src2->nelem - i2) * sizeof (int));
+ id += src2->nelem - i2;
+ }
+ dest->nelem = id;
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets DEST and SRC. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_merge (re_node_set *dest, const re_node_set *src)
+{
+ int is, id, sbase, delta;
+ if (src == NULL || src->nelem == 0)
+ return REG_NOERROR;
+ if (dest->alloc < 2 * src->nelem + dest->nelem)
+ {
+ int new_alloc = 2 * (src->nelem + dest->alloc);
+ int *new_buffer = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_buffer == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_buffer;
+ dest->alloc = new_alloc;
+ }
+
+ if (BE (dest->nelem == 0, 0))
+ {
+ dest->nelem = src->nelem;
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ return REG_NOERROR;
+ }
+
+ /* Copy into the top of DEST the items of SRC that are not
+ found in DEST. Maybe we could binary search in DEST? */
+ for (sbase = dest->nelem + 2 * src->nelem,
+ is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
+ {
+ if (dest->elems[id] == src->elems[is])
+ is--, id--;
+ else if (dest->elems[id] < src->elems[is])
+ dest->elems[--sbase] = src->elems[is--];
+ else /* if (dest->elems[id] > src->elems[is]) */
+ --id;
+ }
+
+ if (is >= 0)
+ {
+ /* If DEST is exhausted, the remaining items of SRC must be unique. */
+ sbase -= is + 1;
+ memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + 2 * src->nelem - 1;
+ delta = is - sbase + 1;
+ if (delta == 0)
+ return REG_NOERROR;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place. */
+ dest->nelem += delta;
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ {
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase,
+ delta * sizeof (int));
+ break;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have ELEM.
+ return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert (re_node_set *set, int elem)
+{
+ int idx;
+ /* In case the set is empty. */
+ if (set->alloc == 0)
+ {
+ if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
+ return 1;
+ else
+ return -1;
+ }
+
+ if (BE (set->nelem, 0) == 0)
+ {
+ /* We already guaranteed above that set->alloc != 0. */
+ set->elems[0] = elem;
+ ++set->nelem;
+ return 1;
+ }
+
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = set->alloc * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Move the elements which follows the new element. Test the
+ first element separately to skip a check in the inner loop. */
+ if (elem < set->elems[0])
+ {
+ idx = 0;
+ for (idx = set->nelem; idx > 0; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+ else
+ {
+ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+
+ /* Insert the new element. */
+ set->elems[idx] = elem;
+ ++set->nelem;
+ return 1;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have any element greater than or equal to ELEM.
+ Return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert_last (re_node_set *set, int elem)
+{
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = (set->alloc + 1) * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Insert the new element. */
+ set->elems[set->nelem++] = elem;
+ return 1;
+}
+
+/* Compare two node sets SET1 and SET2.
+ return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
+{
+ int i;
+ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
+ return 0;
+ for (i = set1->nelem ; --i >= 0 ; )
+ if (set1->elems[i] != set2->elems[i])
+ return 0;
+ return 1;
+}
+
+/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_contains (const re_node_set *set, int elem)
+{
+ unsigned int idx, right, mid;
+ if (set->nelem <= 0)
+ return 0;
+
+ /* Binary search the element. */
+ idx = 0;
+ right = set->nelem - 1;
+ while (idx < right)
+ {
+ mid = (idx + right) / 2;
+ if (set->elems[mid] < elem)
+ idx = mid + 1;
+ else
+ right = mid;
+ }
+ return set->elems[idx] == elem ? idx + 1 : 0;
+}
+
+static void
+internal_function
+re_node_set_remove_at (re_node_set *set, int idx)
+{
+ if (idx < 0 || idx >= set->nelem)
+ return;
+ --set->nelem;
+ for (; idx < set->nelem; idx++)
+ set->elems[idx] = set->elems[idx + 1];
+}
+
+
+/* Add the token TOKEN to dfa->nodes, and return the index of the token.
+ Or return -1, if an error will be occured. */
+
+static int
+internal_function
+re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
+{
+ int type = token.type;
+ if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
+ {
+ size_t new_nodes_alloc = dfa->nodes_alloc * 2;
+ int *new_nexts, *new_indices;
+ re_node_set *new_edests, *new_eclosures;
+ re_token_t *new_nodes;
+
+ /* Avoid overflows. */
+ if (BE (new_nodes_alloc < dfa->nodes_alloc, 0))
+ return -1;
+
+ new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
+ if (BE (new_nodes == NULL, 0))
+ return -1;
+ dfa->nodes = new_nodes;
+ new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
+ new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
+ new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
+ new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
+ if (BE (new_nexts == NULL || new_indices == NULL
+ || new_edests == NULL || new_eclosures == NULL, 0))
+ return -1;
+ dfa->nexts = new_nexts;
+ dfa->org_indices = new_indices;
+ dfa->edests = new_edests;
+ dfa->eclosures = new_eclosures;
+ dfa->nodes_alloc = new_nodes_alloc;
+ }
+ dfa->nodes[dfa->nodes_len] = token;
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+#ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+ (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
+#endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+ re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
+ return dfa->nodes_len++;
+}
+
+static inline unsigned int
+internal_function
+calc_state_hash (const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash = nodes->nelem + context;
+ int i;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ hash += nodes->elems[i];
+ return hash;
+}
+
+/* Search for the state whose node_set is equivalent to NODES.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (BE (nodes->nelem == 0, 0))
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, 0);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (hash != state->hash)
+ continue;
+ if (re_node_set_compare (&state->nodes, nodes))
+ return state;
+ }
+
+ /* There are no appropriate state in the dfa, create the new one. */
+ new_state = create_ci_newstate (dfa, nodes, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Search for the state whose node_set is equivalent to NODES and
+ whose context is equivalent to CONTEXT.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (nodes->nelem == 0)
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, context);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (state->hash == hash
+ && state->context == context
+ && re_node_set_compare (state->entrance_nodes, nodes))
+ return state;
+ }
+ /* There are no appropriate state in `dfa', create the new one. */
+ new_state = create_cd_newstate (dfa, nodes, context, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Finish initialization of the new state NEWSTATE, and using its hash value
+ HASH put in the appropriate bucket of DFA's state table. Return value
+ indicates the error code if failed. */
+
+static reg_errcode_t
+register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
+ unsigned int hash)
+{
+ struct re_state_table_entry *spot;
+ reg_errcode_t err;
+ int i;
+
+ newstate->hash = hash;
+ err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < newstate->nodes.nelem; i++)
+ {
+ int elem = newstate->nodes.elems[i];
+ if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
+ re_node_set_insert_last (&newstate->non_eps_nodes, elem);
+ }
+
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+ if (BE (spot->alloc <= spot->num, 0))
+ {
+ int new_alloc = 2 * spot->num + 2;
+ re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
+ new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ spot->array = new_array;
+ spot->alloc = new_alloc;
+ }
+ spot->array[spot->num++] = newstate;
+ return REG_NOERROR;
+}
+
+static void
+free_state (re_dfastate_t *state)
+{
+ re_node_set_free (&state->non_eps_nodes);
+ re_node_set_free (&state->inveclosure);
+ if (state->entrance_nodes != &state->nodes)
+ {
+ re_node_set_free (state->entrance_nodes);
+ re_free (state->entrance_nodes);
+ }
+ re_node_set_free (&state->nodes);
+ re_free (state->word_trtable);
+ re_free (state->trtable);
+ re_free (state);
+}
+
+/* Create the new state which is independ of contexts.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int hash)
+{
+ int i;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->entrance_nodes = &newstate->nodes;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (type == CHARACTER && !node->constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR || node->constraint)
+ newstate->has_constraint = 1;
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+/* Create the new state which is depend on the context CONTEXT.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int context, unsigned int hash)
+{
+ int i, nctx_nodes = 0;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->context = context;
+ newstate->entrance_nodes = &newstate->nodes;
+
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ unsigned int constraint = 0;
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (node->constraint)
+ constraint = node->constraint;
+
+ if (type == CHARACTER && !constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR)
+ constraint = node->opr.ctx_type;
+
+ if (constraint)
+ {
+ if (newstate->entrance_nodes == &newstate->nodes)
+ {
+ newstate->entrance_nodes = re_malloc (re_node_set, 1);
+ if (BE (newstate->entrance_nodes == NULL, 0))
+ {
+ free_state (newstate);
+ return NULL;
+ }
+ re_node_set_init_copy (newstate->entrance_nodes, nodes);
+ nctx_nodes = 0;
+ newstate->has_constraint = 1;
+ }
+
+ if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
+ {
+ re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
+ ++nctx_nodes;
+ }
+ }
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
diff --git a/libc/posix/regex_internal.h b/libc/posix/regex_internal.h
new file mode 100644
index 000000000..3b575c3c4
--- /dev/null
+++ b/libc/posix/regex_internal.h
@@ -0,0 +1,763 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+# include <langinfo.h>
+#endif
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+#if defined HAVE_WCHAR_H || defined _LIBC
+# include <wchar.h>
+#endif /* HAVE_WCHAR_H || _LIBC */
+#if defined HAVE_WCTYPE_H || defined _LIBC
+# include <wctype.h>
+#endif /* HAVE_WCTYPE_H || _LIBC */
+#if defined HAVE_STDBOOL_H || defined _LIBC
+# include <stdbool.h>
+#endif /* HAVE_STDBOOL_H || _LIBC */
+#if defined HAVE_STDINT_H || defined _LIBC
+# include <stdint.h>
+#endif /* HAVE_STDINT_H || _LIBC */
+#if defined _LIBC
+# include <bits/libc-lock.h>
+#else
+# define __libc_lock_define(CLASS,NAME)
+# define __libc_lock_init(NAME) do { } while (0)
+# define __libc_lock_lock(NAME) do { } while (0)
+# define __libc_lock_unlock(NAME) do { } while (0)
+#endif
+
+/* In case that the system doesn't have isblank(). */
+#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
+# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
+#endif
+
+#ifdef _LIBC
+# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
+# define _RE_DEFINE_LOCALE_FUNCTIONS 1
+# include <locale/localeinfo.h>
+# include <locale/elem-hash.h>
+# include <locale/coll-lookup.h>
+# endif
+#endif
+
+/* This is for other GNU distributions with internationalized messages. */
+#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+# include <libintl.h>
+# ifdef _LIBC
+# undef gettext
+# define gettext(msgid) \
+ INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
+# endif
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+# define gettext_noop(String) String
+#endif
+
+/* For loser systems without the definition. */
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC
+# define RE_ENABLE_I18N
+#endif
+
+#if __GNUC__ >= 3
+# define BE(expr, val) __builtin_expect (expr, val)
+#else
+# define BE(expr, val) (expr)
+# define inline
+#endif
+
+/* Number of single byte character. */
+#define SBC_MAX 256
+
+#define COLL_ELEM_LEN_MAX 8
+
+/* The character which represents newline. */
+#define NEWLINE_CHAR '\n'
+#define WIDE_NEWLINE_CHAR L'\n'
+
+/* Rename to standard API for using out of glibc. */
+#ifndef _LIBC
+# define __wctype wctype
+# define __iswctype iswctype
+# define __btowc btowc
+# define __mempcpy mempcpy
+# define __wcrtomb wcrtomb
+# define __regfree regfree
+# define attribute_hidden
+#endif /* not _LIBC */
+
+#ifdef __GNUC__
+# define __attribute(arg) __attribute__ (arg)
+#else
+# define __attribute(arg)
+#endif
+
+extern const char __re_error_msgid[] attribute_hidden;
+extern const size_t __re_error_msgid_idx[] attribute_hidden;
+
+/* An integer used to represent a set of bits. It must be unsigned,
+ and must be at least as wide as unsigned int. */
+typedef unsigned long int bitset_word_t;
+/* All bits set in a bitset_word_t. */
+#define BITSET_WORD_MAX ULONG_MAX
+/* Number of bits in a bitset_word_t. */
+#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
+/* Number of bitset_word_t in a bit_set. */
+#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
+typedef bitset_word_t bitset_t[BITSET_WORDS];
+typedef bitset_word_t *re_bitset_ptr_t;
+typedef const bitset_word_t *re_const_bitset_ptr_t;
+
+#define bitset_set(set,i) \
+ (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
+#define bitset_clear(set,i) \
+ (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_contain(set,i) \
+ (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
+#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
+#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
+
+#define PREV_WORD_CONSTRAINT 0x0001
+#define PREV_NOTWORD_CONSTRAINT 0x0002
+#define NEXT_WORD_CONSTRAINT 0x0004
+#define NEXT_NOTWORD_CONSTRAINT 0x0008
+#define PREV_NEWLINE_CONSTRAINT 0x0010
+#define NEXT_NEWLINE_CONSTRAINT 0x0020
+#define PREV_BEGBUF_CONSTRAINT 0x0040
+#define NEXT_ENDBUF_CONSTRAINT 0x0080
+#define WORD_DELIM_CONSTRAINT 0x0100
+#define NOT_WORD_DELIM_CONSTRAINT 0x0200
+
+typedef enum
+{
+ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
+ LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
+ BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
+ BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
+ WORD_DELIM = WORD_DELIM_CONSTRAINT,
+ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
+} re_context_type;
+
+typedef struct
+{
+ int alloc;
+ int nelem;
+ int *elems;
+} re_node_set;
+
+typedef enum
+{
+ NON_TYPE = 0,
+
+ /* Node type, These are used by token, node, tree. */
+ CHARACTER = 1,
+ END_OF_RE = 2,
+ SIMPLE_BRACKET = 3,
+ OP_BACK_REF = 4,
+ OP_PERIOD = 5,
+#ifdef RE_ENABLE_I18N
+ COMPLEX_BRACKET = 6,
+ OP_UTF8_PERIOD = 7,
+#endif /* RE_ENABLE_I18N */
+
+ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
+ when the debugger shows values of this enum type. */
+#define EPSILON_BIT 8
+ OP_OPEN_SUBEXP = EPSILON_BIT | 0,
+ OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
+ OP_ALT = EPSILON_BIT | 2,
+ OP_DUP_ASTERISK = EPSILON_BIT | 3,
+ ANCHOR = EPSILON_BIT | 4,
+
+ /* Tree type, these are used only by tree. */
+ CONCAT = 16,
+ SUBEXP = 17,
+
+ /* Token type, these are used only by token. */
+ OP_DUP_PLUS = 18,
+ OP_DUP_QUESTION,
+ OP_OPEN_BRACKET,
+ OP_CLOSE_BRACKET,
+ OP_CHARSET_RANGE,
+ OP_OPEN_DUP_NUM,
+ OP_CLOSE_DUP_NUM,
+ OP_NON_MATCH_LIST,
+ OP_OPEN_COLL_ELEM,
+ OP_CLOSE_COLL_ELEM,
+ OP_OPEN_EQUIV_CLASS,
+ OP_CLOSE_EQUIV_CLASS,
+ OP_OPEN_CHAR_CLASS,
+ OP_CLOSE_CHAR_CLASS,
+ OP_WORD,
+ OP_NOTWORD,
+ OP_SPACE,
+ OP_NOTSPACE,
+ BACK_SLASH
+
+} re_token_type_t;
+
+#ifdef RE_ENABLE_I18N
+typedef struct
+{
+ /* Multibyte characters. */
+ wchar_t *mbchars;
+
+ /* Collating symbols. */
+# ifdef _LIBC
+ int32_t *coll_syms;
+# endif
+
+ /* Equivalence classes. */
+# ifdef _LIBC
+ int32_t *equiv_classes;
+# endif
+
+ /* Range expressions. */
+# ifdef _LIBC
+ uint32_t *range_starts;
+ uint32_t *range_ends;
+# else /* not _LIBC */
+ wchar_t *range_starts;
+ wchar_t *range_ends;
+# endif /* not _LIBC */
+
+ /* Character classes. */
+ wctype_t *char_classes;
+
+ /* If this character set is the non-matching list. */
+ unsigned int non_match : 1;
+
+ /* # of multibyte characters. */
+ int nmbchars;
+
+ /* # of collating symbols. */
+ int ncoll_syms;
+
+ /* # of equivalence classes. */
+ int nequiv_classes;
+
+ /* # of range expressions. */
+ int nranges;
+
+ /* # of character classes. */
+ int nchar_classes;
+} re_charset_t;
+#endif /* RE_ENABLE_I18N */
+
+typedef struct
+{
+ union
+ {
+ unsigned char c; /* for CHARACTER */
+ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset; /* for COMPLEX_BRACKET */
+#endif /* RE_ENABLE_I18N */
+ int idx; /* for BACK_REF */
+ re_context_type ctx_type; /* for ANCHOR */
+ } opr;
+#if __GNUC__ >= 2
+ re_token_type_t type : 8;
+#else
+ re_token_type_t type;
+#endif
+ unsigned int constraint : 10; /* context constraint */
+ unsigned int duplicated : 1;
+ unsigned int opt_subexp : 1;
+#ifdef RE_ENABLE_I18N
+ unsigned int accept_mb : 1;
+ /* These 2 bits can be moved into the union if needed (e.g. if running out
+ of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
+ unsigned int mb_partial : 1;
+#endif
+ unsigned int word_char : 1;
+} re_token_t;
+
+#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
+
+struct re_string_t
+{
+ /* Indicate the raw buffer which is the original string passed as an
+ argument of regexec(), re_search(), etc.. */
+ const unsigned char *raw_mbs;
+ /* Store the multibyte string. In case of "case insensitive mode" like
+ REG_ICASE, upper cases of the string are stored, otherwise MBS points
+ the same address that RAW_MBS points. */
+ unsigned char *mbs;
+#ifdef RE_ENABLE_I18N
+ /* Store the wide character string which is corresponding to MBS. */
+ wint_t *wcs;
+ int *offsets;
+ mbstate_t cur_state;
+#endif
+ /* Index in RAW_MBS. Each character mbs[i] corresponds to
+ raw_mbs[raw_mbs_idx + i]. */
+ int raw_mbs_idx;
+ /* The length of the valid characters in the buffers. */
+ int valid_len;
+ /* The corresponding number of bytes in raw_mbs array. */
+ int valid_raw_len;
+ /* The length of the buffers MBS and WCS. */
+ int bufs_len;
+ /* The index in MBS, which is updated by re_string_fetch_byte. */
+ int cur_idx;
+ /* length of RAW_MBS array. */
+ int raw_len;
+ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
+ int len;
+ /* End of the buffer may be shorter than its length in the cases such
+ as re_match_2, re_search_2. Then, we use STOP for end of the buffer
+ instead of LEN. */
+ int raw_stop;
+ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
+ int stop;
+
+ /* The context of mbs[0]. We store the context independently, since
+ the context of mbs[0] may be different from raw_mbs[0], which is
+ the beginning of the input string. */
+ unsigned int tip_context;
+ /* The translation passed as a part of an argument of re_compile_pattern. */
+ RE_TRANSLATE_TYPE trans;
+ /* Copy of re_dfa_t's word_char. */
+ re_const_bitset_ptr_t word_char;
+ /* 1 if REG_ICASE. */
+ unsigned char icase;
+ unsigned char is_utf8;
+ unsigned char map_notascii;
+ unsigned char mbs_allocated;
+ unsigned char offsets_needed;
+ unsigned char newline_anchor;
+ unsigned char word_ops_used;
+ int mb_cur_max;
+};
+typedef struct re_string_t re_string_t;
+
+
+struct re_dfa_t;
+typedef struct re_dfa_t re_dfa_t;
+
+#ifndef _LIBC
+# ifdef __i386__
+# define internal_function __attribute ((regparm (3), stdcall))
+# else
+# define internal_function
+# endif
+#endif
+
+static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
+ int new_buf_len)
+ internal_function;
+#ifdef RE_ENABLE_I18N
+static void build_wcs_buffer (re_string_t *pstr) internal_function;
+static int build_wcs_upper_buffer (re_string_t *pstr) internal_function;
+#endif /* RE_ENABLE_I18N */
+static void build_upper_buffer (re_string_t *pstr) internal_function;
+static void re_string_translate_buffer (re_string_t *pstr) internal_function;
+static unsigned int re_string_context_at (const re_string_t *input, int idx,
+ int eflags)
+ internal_function __attribute ((pure));
+#define re_string_peek_byte(pstr, offset) \
+ ((pstr)->mbs[(pstr)->cur_idx + offset])
+#define re_string_fetch_byte(pstr) \
+ ((pstr)->mbs[(pstr)->cur_idx++])
+#define re_string_first_byte(pstr, idx) \
+ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
+#define re_string_is_single_byte_char(pstr, idx) \
+ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
+ || (pstr)->wcs[(idx) + 1] != WEOF))
+#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
+#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
+#define re_string_get_buffer(pstr) ((pstr)->mbs)
+#define re_string_length(pstr) ((pstr)->len)
+#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
+#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
+#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
+
+#include <alloca.h>
+
+#ifndef _LIBC
+# if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots. */
+# define __libc_use_alloca(n) ((n) < 4032)
+# else
+/* alloca is implemented with malloc, so just use malloc. */
+# define __libc_use_alloca(n) 0
+# endif
+#endif
+
+#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
+#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
+#define re_free(p) free (p)
+
+struct bin_tree_t
+{
+ struct bin_tree_t *parent;
+ struct bin_tree_t *left;
+ struct bin_tree_t *right;
+ struct bin_tree_t *first;
+ struct bin_tree_t *next;
+
+ re_token_t token;
+
+ /* `node_idx' is the index in dfa->nodes, if `type' == 0.
+ Otherwise `type' indicate the type of this node. */
+ int node_idx;
+};
+typedef struct bin_tree_t bin_tree_t;
+
+#define BIN_TREE_STORAGE_SIZE \
+ ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
+
+struct bin_tree_storage_t
+{
+ struct bin_tree_storage_t *next;
+ bin_tree_t data[BIN_TREE_STORAGE_SIZE];
+};
+typedef struct bin_tree_storage_t bin_tree_storage_t;
+
+#define CONTEXT_WORD 1
+#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
+#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
+#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
+
+#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
+#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
+#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
+#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
+#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
+
+#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
+#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
+#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
+#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
+
+#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
+ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
+ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
+
+#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
+ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
+ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
+
+struct re_dfastate_t
+{
+ unsigned int hash;
+ re_node_set nodes;
+ re_node_set non_eps_nodes;
+ re_node_set inveclosure;
+ re_node_set *entrance_nodes;
+ struct re_dfastate_t **trtable, **word_trtable;
+ unsigned int context : 4;
+ unsigned int halt : 1;
+ /* If this state can accept `multi byte'.
+ Note that we refer to multibyte characters, and multi character
+ collating elements as `multi byte'. */
+ unsigned int accept_mb : 1;
+ /* If this state has backreference node(s). */
+ unsigned int has_backref : 1;
+ unsigned int has_constraint : 1;
+};
+typedef struct re_dfastate_t re_dfastate_t;
+
+struct re_state_table_entry
+{
+ int num;
+ int alloc;
+ re_dfastate_t **array;
+};
+
+/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
+
+typedef struct
+{
+ int next_idx;
+ int alloc;
+ re_dfastate_t **array;
+} state_array_t;
+
+/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
+
+typedef struct
+{
+ int node;
+ int str_idx; /* The position NODE match at. */
+ state_array_t path;
+} re_sub_match_last_t;
+
+/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
+ And information about the node, whose type is OP_CLOSE_SUBEXP,
+ corresponding to NODE is stored in LASTS. */
+
+typedef struct
+{
+ int str_idx;
+ int node;
+ state_array_t *path;
+ int alasts; /* Allocation size of LASTS. */
+ int nlasts; /* The number of LASTS. */
+ re_sub_match_last_t **lasts;
+} re_sub_match_top_t;
+
+struct re_backref_cache_entry
+{
+ int node;
+ int str_idx;
+ int subexp_from;
+ int subexp_to;
+ char more;
+ char unused;
+ unsigned short int eps_reachable_subexps_map;
+};
+
+typedef struct
+{
+ /* The string object corresponding to the input string. */
+ re_string_t input;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ const re_dfa_t *const dfa;
+#else
+ const re_dfa_t *dfa;
+#endif
+ /* EFLAGS of the argument of regexec. */
+ int eflags;
+ /* Where the matching ends. */
+ int match_last;
+ int last_node;
+ /* The state log used by the matcher. */
+ re_dfastate_t **state_log;
+ int state_log_top;
+ /* Back reference cache. */
+ int nbkref_ents;
+ int abkref_ents;
+ struct re_backref_cache_entry *bkref_ents;
+ int max_mb_elem_len;
+ int nsub_tops;
+ int asub_tops;
+ re_sub_match_top_t **sub_tops;
+} re_match_context_t;
+
+typedef struct
+{
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **limited_states;
+ int last_node;
+ int last_str_idx;
+ re_node_set limits;
+} re_sift_context_t;
+
+struct re_fail_stack_ent_t
+{
+ int idx;
+ int node;
+ regmatch_t *regs;
+ re_node_set eps_via_nodes;
+};
+
+struct re_fail_stack_t
+{
+ int num;
+ int alloc;
+ struct re_fail_stack_ent_t *stack;
+};
+
+struct re_dfa_t
+{
+ re_token_t *nodes;
+ size_t nodes_alloc;
+ size_t nodes_len;
+ int *nexts;
+ int *org_indices;
+ re_node_set *edests;
+ re_node_set *eclosures;
+ re_node_set *inveclosures;
+ struct re_state_table_entry *state_table;
+ re_dfastate_t *init_state;
+ re_dfastate_t *init_state_word;
+ re_dfastate_t *init_state_nl;
+ re_dfastate_t *init_state_begbuf;
+ bin_tree_t *str_tree;
+ bin_tree_storage_t *str_tree_storage;
+ re_bitset_ptr_t sb_char;
+ int str_tree_storage_idx;
+
+ /* number of subexpressions `re_nsub' is in regex_t. */
+ unsigned int state_hash_mask;
+ int init_node;
+ int nbackref; /* The number of backreference in this dfa. */
+
+ /* Bitmap expressing which backreference is used. */
+ bitset_word_t used_bkref_map;
+ bitset_word_t completed_bkref_map;
+
+ unsigned int has_plural_match : 1;
+ /* If this dfa has "multibyte node", which is a backreference or
+ a node which can accept multibyte character or multi character
+ collating element. */
+ unsigned int has_mb_node : 1;
+ unsigned int is_utf8 : 1;
+ unsigned int map_notascii : 1;
+ unsigned int word_ops_used : 1;
+ int mb_cur_max;
+ bitset_t word_char;
+ reg_syntax_t syntax;
+ int *subexp_map;
+#ifdef DEBUG
+ char* re_str;
+#endif
+ __libc_lock_define (, lock)
+};
+
+#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+#define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+#define re_node_set_empty(p) ((p)->nelem = 0)
+#define re_node_set_free(set) re_free ((set)->elems)
+
+
+typedef enum
+{
+ SB_CHAR,
+ MB_CHAR,
+ EQUIV_CLASS,
+ COLL_SYM,
+ CHAR_CLASS
+} bracket_elem_type;
+
+typedef struct
+{
+ bracket_elem_type type;
+ union
+ {
+ unsigned char ch;
+ unsigned char *name;
+ wchar_t wch;
+ } opr;
+} bracket_elem_t;
+
+
+/* Inline functions for bitset operation. */
+static inline void
+bitset_not (bitset_t set)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ set[bitset_i] = ~set[bitset_i];
+}
+
+static inline void
+bitset_merge (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] |= src[bitset_i];
+}
+
+static inline void
+bitset_mask (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] &= src[bitset_i];
+}
+
+#ifdef RE_ENABLE_I18N
+/* Inline functions for re_string. */
+static inline int
+internal_function __attribute ((pure))
+re_string_char_size_at (const re_string_t *pstr, int idx)
+{
+ int byte_idx;
+ if (pstr->mb_cur_max == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+ break;
+ return byte_idx;
+}
+
+static inline wint_t
+internal_function __attribute ((pure))
+re_string_wchar_at (const re_string_t *pstr, int idx)
+{
+ if (pstr->mb_cur_max == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+}
+
+static int
+internal_function __attribute ((pure))
+re_string_elem_size_at (const re_string_t *pstr, int idx)
+{
+# ifdef _LIBC
+ const unsigned char *p, *extra;
+ const int32_t *table, *indirect;
+ int32_t tmp;
+# include <locale/weight.h>
+ uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+
+ if (nrules != 0)
+ {
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ p = pstr->mbs + idx;
+ tmp = findidx (&p);
+ return p - pstr->mbs - idx;
+ }
+ else
+# endif /* _LIBC */
+ return 1;
+}
+#endif /* RE_ENABLE_I18N */
+
+#endif /* _REGEX_INTERNAL_H */
diff --git a/libc/posix/regexbug1.c b/libc/posix/regexbug1.c
new file mode 100644
index 000000000..28640968d
--- /dev/null
+++ b/libc/posix/regexbug1.c
@@ -0,0 +1,51 @@
+#include <error.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ regex_t re;
+ regmatch_t ma[2];
+ int reerr;
+ int res = 0;
+
+ re_set_syntax (RE_DEBUG);
+ reerr = regcomp (&re, "0*[0-9][0-9]", 0);
+ if (reerr != 0)
+ {
+ char buf[100];
+ regerror (reerr, &re, buf, sizeof buf);
+ error (EXIT_FAILURE, 0, buf);
+ }
+
+ if (regexec (&re, "002", 2, ma, 0) != 0)
+ {
+ error (0, 0, "\"0*[0-9][0-9]\" does not match \"002\"");
+ res = 1;
+ }
+ puts ("Succesful match with \"0*[0-9][0-9]\"");
+
+ regfree (&re);
+
+ reerr = regcomp (&re, "[0a]*[0-9][0-9]", 0);
+ if (reerr != 0)
+ {
+ char buf[100];
+ regerror (reerr, &re, buf, sizeof buf);
+ error (EXIT_FAILURE, 0, buf);
+ }
+
+ if (regexec (&re, "002", 2, ma, 0) != 0)
+ {
+ error (0, 0, "\"[0a]*[0-9][0-9]\" does not match \"002\"");
+ res = 1;
+ }
+ puts ("Succesful match with \"[0a]*[0-9][0-9]\"");
+
+ regfree (&re);
+
+ return res;
+}
diff --git a/libc/posix/regexec.c b/libc/posix/regexec.c
new file mode 100644
index 000000000..bdfa3550a
--- /dev/null
+++ b/libc/posix/regexec.c
@@ -0,0 +1,4329 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+static void match_ctx_clean (re_match_context_t *mctx) internal_function;
+static void match_ctx_free (re_match_context_t *cache) internal_function;
+static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
+ int str_idx, int from, int to)
+ internal_function;
+static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+ internal_function;
+static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
+ int str_idx) internal_function;
+static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
+ int node, int str_idx)
+ internal_function;
+static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node,
+ int last_str_idx)
+ internal_function;
+static reg_errcode_t re_search_internal (const regex_t *preg,
+ const char *string, int length,
+ int start, int range, int stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags) internal_function;
+static int re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range, struct re_registers *regs,
+ int stop, int ret_len) internal_function;
+static int re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, int length, int start,
+ int range, int stop, struct re_registers *regs,
+ int ret_len) internal_function;
+static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
+ int nregs, int regs_allocated) internal_function;
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
+static int check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first) internal_function;
+static int check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+ internal_function;
+static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node,
+ int cur_idx, int nmatch) internal_function;
+static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
+ int str_idx, int dest_node, int nregs,
+ regmatch_t *regs,
+ re_node_set *eps_via_nodes)
+ internal_function;
+static reg_errcode_t set_regs (const regex_t *preg,
+ const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch,
+ int fl_backtrack) internal_function;
+static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
+ internal_function;
+
+#ifdef RE_ENABLE_I18N
+static int sift_states_iter_mb (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+ internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
+ re_sift_context_t *sctx)
+ internal_function;
+static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *cur_dest)
+ internal_function;
+static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx,
+ re_node_set *dest_nodes)
+ internal_function;
+static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates)
+ internal_function;
+static int check_dst_limits (const re_match_context_t *mctx,
+ re_node_set *limits,
+ int dst_node, int dst_idx, int src_node,
+ int src_idx) internal_function;
+static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
+ int boundaries, int subexp_idx,
+ int from_node, int bkref_idx)
+ internal_function;
+static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
+ int limit, int subexp_idx,
+ int node, int str_idx,
+ int bkref_idx) internal_function;
+static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates,
+ re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents,
+ int str_idx) internal_function;
+static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+ internal_function;
+static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
+ re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+ internal_function;
+static re_dfastate_t *find_recover_state (reg_errcode_t *err,
+ re_match_context_t *mctx) internal_function;
+static re_dfastate_t *transit_state (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *state) internal_function;
+static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+ internal_function;
+static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
+ re_node_set *cur_nodes,
+ int str_idx) internal_function;
+#if 0
+static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
+ const re_node_set *nodes)
+ internal_function;
+static reg_errcode_t get_subexp (re_match_context_t *mctx,
+ int bkref_node, int bkref_str_idx)
+ internal_function;
+static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
+ const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last,
+ int bkref_node, int bkref_str)
+ internal_function;
+static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type) internal_function;
+static reg_errcode_t check_arrival (re_match_context_t *mctx,
+ state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str,
+ int type) internal_function;
+static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
+ int str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
+ re_node_set *cur_nodes,
+ int ex_subexp, int type)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
+ re_node_set *dst_nodes,
+ int target, int ex_subexp,
+ int type) internal_function;
+static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
+ re_node_set *cur_nodes, int cur_str,
+ int subexp_num, int type)
+ internal_function;
+static int build_trtable (const re_dfa_t *dfa,
+ re_dfastate_t *state) internal_function;
+#ifdef RE_ENABLE_I18N
+static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx)
+ internal_function;
+# ifdef _LIBC
+static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len)
+ internal_function;
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+ re_node_set *states_node,
+ bitset_t *states_ch) internal_function;
+static int check_node_accept (const re_match_context_t *mctx,
+ const re_token_t *node, int idx)
+ internal_function;
+static reg_errcode_t extend_buffers (re_match_context_t *mctx)
+ internal_function;
+
+/* Entry point for POSIX code. */
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *__restrict preg;
+ const char *__restrict string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ reg_errcode_t err;
+ int start, length;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+
+ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
+ return REG_BADPAT;
+
+ if (eflags & REG_STARTEND)
+ {
+ start = pmatch[0].rm_so;
+ length = pmatch[0].rm_eo;
+ }
+ else
+ {
+ start = 0;
+ length = strlen (string);
+ }
+
+ __libc_lock_lock (dfa->lock);
+ if (preg->no_sub)
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, 0, NULL, eflags);
+ else
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, nmatch, pmatch, eflags);
+ __libc_lock_unlock (dfa->lock);
+ return err != REG_NOERROR;
+}
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+__typeof__ (__regexec) __compat_regexec;
+
+int
+attribute_compat_text_section
+__compat_regexec (const regex_t *__restrict preg,
+ const char *__restrict string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ return regexec (preg, string, nmatch, pmatch,
+ eflags & (REG_NOTBOL | REG_NOTEOL));
+}
+compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+# endif
+#endif
+
+/* Entry points for GNU code. */
+
+/* re_match, re_search, re_match_2, re_search_2
+
+ The former two functions operate on STRING with length LENGTH,
+ while the later two operate on concatenation of STRING1 and STRING2
+ with lengths LENGTH1 and LENGTH2, respectively.
+
+ re_match() matches the compiled pattern in BUFP against the string,
+ starting at index START.
+
+ re_search() first tries matching at index START, then it tries to match
+ starting from index START + 1, and so on. The last start position tried
+ is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
+ way as re_match().)
+
+ The parameter STOP of re_{match,search}_2 specifies that no match exceeding
+ the first STOP characters of the concatenation of the strings should be
+ concerned.
+
+ If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
+ and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ computed relative to the concatenation, not relative to the individual
+ strings.)
+
+ On success, re_match* functions return the length of the match, re_search*
+ return the position of the start of the match. Return value -1 means no
+ match was found and -2 indicates an internal error. */
+
+int
+re_match (bufp, string, length, start, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match, re_match)
+#endif
+
+int
+re_search (bufp, string, length, start, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, range, length, regs, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+int
+re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, 0, regs, stop, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+int
+re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, range, regs, stop, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+static int
+re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs,
+ stop, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ const char *str;
+ int rval;
+ int len = length1 + length2;
+ int free_str = 0;
+
+ if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
+ return -2;
+
+ /* Concatenate the strings. */
+ if (length2 > 0)
+ if (length1 > 0)
+ {
+ char *s = re_malloc (char, len);
+
+ if (BE (s == NULL, 0))
+ return -2;
+#ifdef _LIBC
+ memcpy (__mempcpy (s, string1, length1), string2, length2);
+#else
+ memcpy (s, string1, length1);
+ memcpy (s + length1, string2, length2);
+#endif
+ str = s;
+ free_str = 1;
+ }
+ else
+ str = string2;
+ else
+ str = string1;
+
+ rval = re_search_stub (bufp, str, len, start, range, stop, regs,
+ ret_len);
+ if (free_str)
+ re_free ((char *) str);
+ return rval;
+}
+
+/* The parameters have the same meaning as those of re_search.
+ Additional parameters:
+ If RET_LEN is nonzero the length of the match is returned (re_match style);
+ otherwise the position of the match is returned. */
+
+static int
+re_search_stub (bufp, string, length, start, range, stop, regs, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ reg_errcode_t result;
+ regmatch_t *pmatch;
+ int nregs, rval;
+ int eflags = 0;
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+
+ /* Check for out-of-range. */
+ if (BE (start < 0 || start > length, 0))
+ return -1;
+ if (BE (start + range > length, 0))
+ range = length - start;
+ else if (BE (start + range < 0, 0))
+ range = -start;
+
+ __libc_lock_lock (dfa->lock);
+
+ eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
+ eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
+
+ /* Compile fastmap if we haven't yet. */
+ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
+ re_compile_fastmap (bufp);
+
+ if (BE (bufp->no_sub, 0))
+ regs = NULL;
+
+ /* We need at least 1 register. */
+ if (regs == NULL)
+ nregs = 1;
+ else if (BE (bufp->regs_allocated == REGS_FIXED &&
+ regs->num_regs < bufp->re_nsub + 1, 0))
+ {
+ nregs = regs->num_regs;
+ if (BE (nregs < 1, 0))
+ {
+ /* Nothing can be copied to regs. */
+ regs = NULL;
+ nregs = 1;
+ }
+ }
+ else
+ nregs = bufp->re_nsub + 1;
+ pmatch = re_malloc (regmatch_t, nregs);
+ if (BE (pmatch == NULL, 0))
+ {
+ rval = -2;
+ goto out;
+ }
+
+ result = re_search_internal (bufp, string, length, start, range, stop,
+ nregs, pmatch, eflags);
+
+ rval = 0;
+
+ /* I hope we needn't fill ther regs with -1's when no match was found. */
+ if (result != REG_NOERROR)
+ rval = -1;
+ else if (regs != NULL)
+ {
+ /* If caller wants register contents data back, copy them. */
+ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->regs_allocated);
+ if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
+ rval = -2;
+ }
+
+ if (BE (rval == 0, 1))
+ {
+ if (ret_len)
+ {
+ assert (pmatch[0].rm_so == start);
+ rval = pmatch[0].rm_eo - start;
+ }
+ else
+ rval = pmatch[0].rm_so;
+ }
+ re_free (pmatch);
+ out:
+ __libc_lock_unlock (dfa->lock);
+ return rval;
+}
+
+static unsigned
+re_copy_regs (regs, pmatch, nregs, regs_allocated)
+ struct re_registers *regs;
+ regmatch_t *pmatch;
+ int nregs, regs_allocated;
+{
+ int rval = REGS_REALLOCATE;
+ int i;
+ int need_regs = nregs + 1;
+ /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
+ uses. */
+
+ /* Have the register data arrays been allocated? */
+ if (regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. */
+ regs->start = re_malloc (regoff_t, need_regs);
+ regs->end = re_malloc (regoff_t, need_regs);
+ if (BE (regs->start == NULL, 0) || BE (regs->end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->num_regs = need_regs;
+ }
+ else if (regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (BE (need_regs > regs->num_regs, 0))
+ {
+ regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
+ regoff_t *new_end = re_realloc (regs->end, regoff_t, need_regs);
+ if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->start = new_start;
+ regs->end = new_end;
+ regs->num_regs = need_regs;
+ }
+ }
+ else
+ {
+ assert (regs_allocated == REGS_FIXED);
+ /* This function may not be called with REGS_FIXED and nregs too big. */
+ assert (regs->num_regs >= nregs);
+ rval = REGS_FIXED;
+ }
+
+ /* Copy the regs. */
+ for (i = 0; i < nregs; ++i)
+ {
+ regs->start[i] = pmatch[i].rm_so;
+ regs->end[i] = pmatch[i].rm_eo;
+ }
+ for ( ; i < regs->num_regs; ++i)
+ regs->start[i] = regs->end[i] = -1;
+
+ return rval;
+}
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+int
+# ifdef _LIBC
+weak_function
+# endif
+re_exec (s)
+ const char *s;
+{
+ return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point. */
+
+/* Searches for a compiled pattern PREG in the string STRING, whose
+ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
+ mingings with regexec. START, and RANGE have the same meanings
+ with re_search.
+ Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
+ otherwise return the error code.
+ Note: We assume front end functions already check ranges.
+ (START + RANGE >= 0 && START + RANGE <= LENGTH) */
+
+static reg_errcode_t
+re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch,
+ eflags)
+ const regex_t *preg;
+ const char *string;
+ int length, start, range, stop, eflags;
+ size_t nmatch;
+ regmatch_t pmatch[];
+{
+ reg_errcode_t err;
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int left_lim, right_lim, incr;
+ int fl_longest_match, match_first, match_kind, match_last = -1;
+ int extra_nmatch;
+ int sb, ch;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_match_context_t mctx = { .dfa = dfa };
+#else
+ re_match_context_t mctx;
+#endif
+ char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
+ && range && !preg->can_be_null) ? preg->fastmap : NULL;
+ RE_TRANSLATE_TYPE t = preg->translate;
+
+#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
+ memset (&mctx, '\0', sizeof (re_match_context_t));
+ mctx.dfa = dfa;
+#endif
+
+ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
+ nmatch -= extra_nmatch;
+
+ /* Check if the DFA haven't been compiled. */
+ if (BE (preg->used == 0 || dfa->init_state == NULL
+ || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return REG_NOMATCH;
+
+#ifdef DEBUG
+ /* We assume front-end functions already check them. */
+ assert (start + range >= 0 && start + range <= length);
+#endif
+
+ /* If initial states with non-begbuf contexts have no elements,
+ the regex must be anchored. If preg->newline_anchor is set,
+ we'll never use init_state_nl, so do not check it. */
+ if (dfa->init_state->nodes.nelem == 0
+ && dfa->init_state_word->nodes.nelem == 0
+ && (dfa->init_state_nl->nodes.nelem == 0
+ || !preg->newline_anchor))
+ {
+ if (start != 0 && start + range != 0)
+ return REG_NOMATCH;
+ start = range = 0;
+ }
+
+ /* We must check the longest matching, if nmatch > 0. */
+ fl_longest_match = (nmatch != 0 || dfa->nbackref);
+
+ err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
+ preg->translate, preg->syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ mctx.input.stop = stop;
+ mctx.input.raw_stop = stop;
+ mctx.input.newline_anchor = preg->newline_anchor;
+
+ err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* We will log all the DFA states through which the dfa pass,
+ if nmatch > 1, or this dfa has "multibyte node", which is a
+ back-reference or a node which can accept multibyte character or
+ multi character collating element. */
+ if (nmatch > 1 || dfa->has_mb_node)
+ {
+ mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
+ if (BE (mctx.state_log == NULL, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ }
+ else
+ mctx.state_log = NULL;
+
+ match_first = start;
+ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
+
+ /* Check incrementally whether of not the input string match. */
+ incr = (range < 0) ? -1 : 1;
+ left_lim = (range < 0) ? start + range : start;
+ right_lim = (range < 0) ? start : start + range;
+ sb = dfa->mb_cur_max == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+ | (range >= 0 ? 2 : 0)
+ | (t != NULL ? 1 : 0))
+ : 8);
+
+ for (;; match_first += incr)
+ {
+ err = REG_NOMATCH;
+ if (match_first < left_lim || right_lim < match_first)
+ goto free_return;
+
+ /* Advance as rapidly as possible through the string, until we
+ find a plausible place to start matching. This may be done
+ with varying efficiency, so there are various possibilities:
+ only the most common of them are specialized, in order to
+ save on code size. We use a switch statement for speed. */
+ switch (match_kind)
+ {
+ case 8:
+ /* No fastmap. */
+ break;
+
+ case 7:
+ /* Fastmap with single-byte translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[t[(unsigned char) string[match_first]]])
+ ++match_first;
+ goto forward_match_found_start_or_reached_end;
+
+ case 6:
+ /* Fastmap without translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[(unsigned char) string[match_first]])
+ ++match_first;
+
+ forward_match_found_start_or_reached_end:
+ if (BE (match_first == right_lim, 0))
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (!fastmap[t ? t[ch] : ch])
+ goto free_return;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Fastmap without multi-byte translation, match backwards. */
+ while (match_first >= left_lim)
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (fastmap[t ? t[ch] : ch])
+ break;
+ --match_first;
+ }
+ if (match_first < left_lim)
+ goto free_return;
+ break;
+
+ default:
+ /* In this case, we can't determine easily the current byte,
+ since it might be a component byte of a multibyte
+ character. Then we use the constructed buffer instead. */
+ for (;;)
+ {
+ /* If MATCH_FIRST is out of the valid range, reconstruct the
+ buffers. */
+ unsigned int offset = match_first - mctx.input.raw_mbs_idx;
+ if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
+ {
+ err = re_string_reconstruct (&mctx.input, match_first,
+ eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ offset = match_first - mctx.input.raw_mbs_idx;
+ }
+ /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
+ Note that MATCH_FIRST must not be smaller than 0. */
+ ch = (match_first >= length
+ ? 0 : re_string_byte_at (&mctx.input, offset));
+ if (fastmap[ch])
+ break;
+ match_first += incr;
+ if (match_first < left_lim || match_first > right_lim)
+ {
+ err = REG_NOMATCH;
+ goto free_return;
+ }
+ }
+ break;
+ }
+
+ /* Reconstruct the buffers so that the matcher can assume that
+ the matching starts from the beginning of the buffer. */
+ err = re_string_reconstruct (&mctx.input, match_first, eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* Don't consider this char as a possible match start if it part,
+ yet isn't the head, of a multibyte character. */
+ if (!sb && !re_string_first_byte (&mctx.input, 0))
+ continue;
+#endif
+
+ /* It seems to be appropriate one, then use the matcher. */
+ /* We assume that the matching starts from 0. */
+ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
+ match_last = check_matching (&mctx, fl_longest_match,
+ range >= 0 ? &match_first : NULL);
+ if (match_last != -1)
+ {
+ if (BE (match_last == -2, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ else
+ {
+ mctx.match_last = match_last;
+ if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
+ {
+ re_dfastate_t *pstate = mctx.state_log[match_last];
+ mctx.last_node = check_halt_state_context (&mctx, pstate,
+ match_last);
+ }
+ if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ err = prune_impossible_nodes (&mctx);
+ if (err == REG_NOERROR)
+ break;
+ if (BE (err != REG_NOMATCH, 0))
+ goto free_return;
+ match_last = -1;
+ }
+ else
+ break; /* We found a match. */
+ }
+ }
+
+ match_ctx_clean (&mctx);
+ }
+
+#ifdef DEBUG
+ assert (match_last != -1);
+ assert (err == REG_NOERROR);
+#endif
+
+ /* Set pmatch[] if we need. */
+ if (nmatch > 0)
+ {
+ int reg_idx;
+
+ /* Initialize registers. */
+ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
+ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
+
+ /* Set the points where matching start/end. */
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = mctx.match_last;
+
+ if (!preg->no_sub && nmatch > 1)
+ {
+ err = set_regs (preg, &mctx, nmatch, pmatch,
+ dfa->has_plural_match && dfa->nbackref > 0);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* At last, add the offset to the each registers, since we slided
+ the buffers so that we could assume that the matching starts
+ from 0. */
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so != -1)
+ {
+#ifdef RE_ENABLE_I18N
+ if (BE (mctx.input.offsets_needed != 0, 0))
+ {
+ pmatch[reg_idx].rm_so =
+ (pmatch[reg_idx].rm_so == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_so]);
+ pmatch[reg_idx].rm_eo =
+ (pmatch[reg_idx].rm_eo == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
+ }
+#else
+ assert (mctx.input.offsets_needed == 0);
+#endif
+ pmatch[reg_idx].rm_so += match_first;
+ pmatch[reg_idx].rm_eo += match_first;
+ }
+ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
+ {
+ pmatch[nmatch + reg_idx].rm_so = -1;
+ pmatch[nmatch + reg_idx].rm_eo = -1;
+ }
+
+ if (dfa->subexp_map)
+ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
+ if (dfa->subexp_map[reg_idx] != reg_idx)
+ {
+ pmatch[reg_idx + 1].rm_so
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
+ pmatch[reg_idx + 1].rm_eo
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
+ }
+ }
+
+ free_return:
+ re_free (mctx.state_log);
+ if (dfa->nbackref)
+ match_ctx_free (&mctx);
+ re_string_destruct (&mctx.input);
+ return err;
+}
+
+static reg_errcode_t
+prune_impossible_nodes (mctx)
+ re_match_context_t *mctx;
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int halt_node, match_last;
+ reg_errcode_t ret;
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **lim_states = NULL;
+ re_sift_context_t sctx;
+#ifdef DEBUG
+ assert (mctx->state_log != NULL);
+#endif
+ match_last = mctx->match_last;
+ halt_node = mctx->last_node;
+ sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (sifted_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ if (dfa->nbackref)
+ {
+ lim_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (lim_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ while (1)
+ {
+ memset (lim_states, '\0',
+ sizeof (re_dfastate_t *) * (match_last + 1));
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
+ match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ if (sifted_states[0] != NULL || lim_states[0] != NULL)
+ break;
+ do
+ {
+ --match_last;
+ if (match_last < 0)
+ {
+ ret = REG_NOMATCH;
+ goto free_return;
+ }
+ } while (mctx->state_log[match_last] == NULL
+ || !mctx->state_log[match_last]->halt);
+ halt_node = check_halt_state_context (mctx,
+ mctx->state_log[match_last],
+ match_last);
+ }
+ ret = merge_state_array (dfa, sifted_states, lim_states,
+ match_last + 1);
+ re_free (lim_states);
+ lim_states = NULL;
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ re_free (mctx->state_log);
+ mctx->state_log = sifted_states;
+ sifted_states = NULL;
+ mctx->last_node = halt_node;
+ mctx->match_last = match_last;
+ ret = REG_NOERROR;
+ free_return:
+ re_free (sifted_states);
+ re_free (lim_states);
+ return ret;
+}
+
+/* Acquire an initial state and return it.
+ We must select appropriate initial state depending on the context,
+ since initial states may have constraints like "\<", "^", etc.. */
+
+static inline re_dfastate_t *
+__attribute ((always_inline)) internal_function
+acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
+ int idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ if (dfa->init_state->has_constraint)
+ {
+ unsigned int context;
+ context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return dfa->init_state_word;
+ else if (IS_ORDINARY_CONTEXT (context))
+ return dfa->init_state;
+ else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_begbuf;
+ else if (IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_nl;
+ else if (IS_BEGBUF_CONTEXT (context))
+ {
+ /* It is relatively rare case, then calculate on demand. */
+ return re_acquire_state_context (err, dfa,
+ dfa->init_state->entrance_nodes,
+ context);
+ }
+ else
+ /* Must not happen? */
+ return dfa->init_state;
+ }
+ else
+ return dfa->init_state;
+}
+
+/* Check whether the regular expression match input string INPUT or not,
+ and return the index where the matching end, return -1 if not match,
+ or return -2 in case of an error.
+ FL_LONGEST_MATCH means we want the POSIX longest matching.
+ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
+ next place where we may want to try matching.
+ Note that the matcher assume that the maching starts from the current
+ index of the buffer. */
+
+static int
+internal_function
+check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int match = 0;
+ int match_last = -1;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+ re_dfastate_t *cur_state;
+ int at_init_state = p_match_first != NULL;
+ int next_start_idx = cur_str_idx;
+
+ err = REG_NOERROR;
+ cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
+ /* An initial state must not be NULL (invalid). */
+ if (BE (cur_state == NULL, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+
+ if (mctx->state_log != NULL)
+ {
+ mctx->state_log[cur_str_idx] = cur_state;
+
+ /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
+ later. E.g. Processing back references. */
+ if (BE (dfa->nbackref, 0))
+ {
+ at_init_state = 0;
+ err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (cur_state->has_backref)
+ {
+ err = transit_state_bkref (mctx, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+
+ /* If the RE accepts NULL string. */
+ if (BE (cur_state->halt, 0))
+ {
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state, cur_str_idx))
+ {
+ if (!fl_longest_match)
+ return cur_str_idx;
+ else
+ {
+ match_last = cur_str_idx;
+ match = 1;
+ }
+ }
+ }
+
+ while (!re_string_eoi (&mctx->input))
+ {
+ re_dfastate_t *old_state = cur_state;
+ int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
+
+ if (BE (next_char_idx >= mctx->input.bufs_len, 0)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+ }
+
+ cur_state = transit_state (&err, mctx, cur_state);
+ if (mctx->state_log != NULL)
+ cur_state = merge_state_with_log (&err, mctx, cur_state);
+
+ if (cur_state == NULL)
+ {
+ /* Reached the invalid state or an error. Try to recover a valid
+ state using the state log, if available and if we have not
+ already found a valid (even if not the longest) match. */
+ if (BE (err != REG_NOERROR, 0))
+ return -2;
+
+ if (mctx->state_log == NULL
+ || (match && !fl_longest_match)
+ || (cur_state = find_recover_state (&err, mctx)) == NULL)
+ break;
+ }
+
+ if (BE (at_init_state, 0))
+ {
+ if (old_state == cur_state)
+ next_start_idx = next_char_idx;
+ else
+ at_init_state = 0;
+ }
+
+ if (cur_state->halt)
+ {
+ /* Reached a halt state.
+ Check the halt state can satisfy the current context. */
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state,
+ re_string_cur_idx (&mctx->input)))
+ {
+ /* We found an appropriate halt state. */
+ match_last = re_string_cur_idx (&mctx->input);
+ match = 1;
+
+ /* We found a match, do not modify match_first below. */
+ p_match_first = NULL;
+ if (!fl_longest_match)
+ break;
+ }
+ }
+ }
+
+ if (p_match_first)
+ *p_match_first += next_start_idx;
+
+ return match_last;
+}
+
+/* Check NODE match the current context. */
+
+static int
+internal_function
+check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context)
+{
+ re_token_type_t type = dfa->nodes[node].type;
+ unsigned int constraint = dfa->nodes[node].constraint;
+ if (type != END_OF_RE)
+ return 0;
+ if (!constraint)
+ return 1;
+ if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
+ return 0;
+ return 1;
+}
+
+/* Check the halt state STATE match the current context.
+ Return 0 if not match, if the node, STATE has, is a halt node and
+ match the context, return the node. */
+
+static int
+internal_function
+check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+{
+ int i;
+ unsigned int context;
+#ifdef DEBUG
+ assert (state->halt);
+#endif
+ context = re_string_context_at (&mctx->input, idx, mctx->eflags);
+ for (i = 0; i < state->nodes.nelem; ++i)
+ if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
+ return state->nodes.elems[i];
+ return 0;
+}
+
+/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
+ corresponding to the DFA).
+ Return the destination node, and update EPS_VIA_NODES, return -1 in case
+ of errors. */
+
+static int
+internal_function
+proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs,
+ int *pidx, int node, re_node_set *eps_via_nodes,
+ struct re_fail_stack_t *fs)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int i, err;
+ if (IS_EPSILON_NODE (dfa->nodes[node].type))
+ {
+ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
+ re_node_set *edests = &dfa->edests[node];
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ /* Pick up a valid destination, or return -1 if none is found. */
+ for (dest_node = -1, i = 0; i < edests->nelem; ++i)
+ {
+ int candidate = edests->elems[i];
+ if (!re_node_set_contains (cur_nodes, candidate))
+ continue;
+ if (dest_node == -1)
+ dest_node = candidate;
+
+ else
+ {
+ /* In order to avoid infinite loop like "(a*)*", return the second
+ epsilon-transition if the first was already considered. */
+ if (re_node_set_contains (eps_via_nodes, dest_node))
+ return candidate;
+
+ /* Otherwise, push the second epsilon-transition on the fail stack. */
+ else if (fs != NULL
+ && push_fail_stack (fs, *pidx, candidate, nregs, regs,
+ eps_via_nodes))
+ return -2;
+
+ /* We know we are going to exit. */
+ break;
+ }
+ }
+ return dest_node;
+ }
+ else
+ {
+ int naccepted = 0;
+ re_token_type_t type = dfa->nodes[node].type;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->nodes[node].accept_mb)
+ naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (type == OP_BACK_REF)
+ {
+ int subexp_idx = dfa->nodes[node].opr.idx + 1;
+ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
+ if (fs != NULL)
+ {
+ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
+ return -1;
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted) != 0)
+ return -1;
+ }
+ }
+
+ if (naccepted == 0)
+ {
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ dest_node = dfa->edests[node].elems[0];
+ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node))
+ return dest_node;
+ }
+ }
+
+ if (naccepted != 0
+ || check_node_accept (mctx, dfa->nodes + node, *pidx))
+ {
+ int dest_node = dfa->nexts[node];
+ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
+ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
+ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node)))
+ return -1;
+ re_node_set_empty (eps_via_nodes);
+ return dest_node;
+ }
+ }
+ return -1;
+}
+
+static reg_errcode_t
+internal_function
+push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node,
+ int nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ reg_errcode_t err;
+ int num = fs->num++;
+ if (fs->num == fs->alloc)
+ {
+ struct re_fail_stack_ent_t *new_array;
+ new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
+ * fs->alloc * 2));
+ if (new_array == NULL)
+ return REG_ESPACE;
+ fs->alloc *= 2;
+ fs->stack = new_array;
+ }
+ fs->stack[num].idx = str_idx;
+ fs->stack[num].node = dest_node;
+ fs->stack[num].regs = re_malloc (regmatch_t, nregs);
+ if (fs->stack[num].regs == NULL)
+ return REG_ESPACE;
+ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
+ return err;
+}
+
+static int
+internal_function
+pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
+ regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ int num = --fs->num;
+ assert (num >= 0);
+ *pidx = fs->stack[num].idx;
+ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+ re_node_set_free (eps_via_nodes);
+ re_free (fs->stack[num].regs);
+ *eps_via_nodes = fs->stack[num].eps_via_nodes;
+ return fs->stack[num].node;
+}
+
+/* Set the positions where the subexpressions are starts/ends to registers
+ PMATCH.
+ Note: We assume that pmatch[0] is already set, and
+ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
+
+static reg_errcode_t
+internal_function
+set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
+ regmatch_t *pmatch, int fl_backtrack)
+{
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int idx, cur_node;
+ re_node_set eps_via_nodes;
+ struct re_fail_stack_t *fs;
+ struct re_fail_stack_t fs_body = { 0, 2, NULL };
+ regmatch_t *prev_idx_match;
+ int prev_idx_match_malloced = 0;
+
+#ifdef DEBUG
+ assert (nmatch > 1);
+ assert (mctx->state_log != NULL);
+#endif
+ if (fl_backtrack)
+ {
+ fs = &fs_body;
+ fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
+ if (fs->stack == NULL)
+ return REG_ESPACE;
+ }
+ else
+ fs = NULL;
+
+ cur_node = dfa->init_node;
+ re_node_set_init_empty (&eps_via_nodes);
+
+ if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
+ prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
+ else
+ {
+ prev_idx_match = re_malloc (regmatch_t, nmatch);
+ if (prev_idx_match == NULL)
+ {
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ prev_idx_match_malloced = 1;
+ }
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+
+ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
+ {
+ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+
+ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+ {
+ int reg_idx;
+ if (fs)
+ {
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
+ break;
+ if (reg_idx == nmatch)
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+ }
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ }
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOERROR;
+ }
+ }
+
+ /* Proceed to next node. */
+ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+ &eps_via_nodes, fs);
+
+ if (BE (cur_node < 0, 0))
+ {
+ if (BE (cur_node == -2, 0))
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (fs)
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOMATCH;
+ }
+ }
+ }
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+}
+
+static reg_errcode_t
+internal_function
+free_fail_stack_return (struct re_fail_stack_t *fs)
+{
+ if (fs)
+ {
+ int fs_idx;
+ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
+ {
+ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
+ re_free (fs->stack[fs_idx].regs);
+ }
+ re_free (fs->stack);
+ }
+ return REG_NOERROR;
+}
+
+static void
+internal_function
+update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch)
+{
+ int type = dfa->nodes[cur_node].type;
+ if (type == OP_OPEN_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+
+ /* We are at the first node of this sub expression. */
+ if (reg_num < nmatch)
+ {
+ pmatch[reg_num].rm_so = cur_idx;
+ pmatch[reg_num].rm_eo = -1;
+ }
+ }
+ else if (type == OP_CLOSE_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+ if (reg_num < nmatch)
+ {
+ /* We are at the last node of this sub expression. */
+ if (pmatch[reg_num].rm_so < cur_idx)
+ {
+ pmatch[reg_num].rm_eo = cur_idx;
+ /* This is a non-empty match or we are not inside an optional
+ subexpression. Accept this right away. */
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+ }
+ else
+ {
+ if (dfa->nodes[cur_node].opt_subexp
+ && prev_idx_match[reg_num].rm_so != -1)
+ /* We transited through an empty match for an optional
+ subexpression, like (a?)*, and this is not the subexp's
+ first match. Copy back the old content of the registers
+ so that matches of an inner subexpression are undone as
+ well, like in ((a?))*. */
+ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
+ else
+ /* We completed a subexpression, but it may be part of
+ an optional one, so do not update PREV_IDX_MATCH. */
+ pmatch[reg_num].rm_eo = cur_idx;
+ }
+ }
+ }
+}
+
+/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
+ and sift the nodes in each states according to the following rules.
+ Updated state_log will be wrote to STATE_LOG.
+
+ Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
+ 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
+ If `a' isn't the LAST_NODE and `a' can't epsilon transit to
+ the LAST_NODE, we throw away the node `a'.
+ 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
+ string `s' and transit to `b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
+ away the node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
+ thrown away, we throw away the node `a'.
+ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
+ node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
+ we throw away the node `a'. */
+
+#define STATE_NODE_CONTAINS(state,node) \
+ ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
+
+static reg_errcode_t
+internal_function
+sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
+{
+ reg_errcode_t err;
+ int null_cnt = 0;
+ int str_idx = sctx->last_str_idx;
+ re_node_set cur_dest;
+
+#ifdef DEBUG
+ assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
+#endif
+
+ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
+ transit to the last_node and the last_node itself. */
+ err = re_node_set_init_1 (&cur_dest, sctx->last_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* Then check each states in the state_log. */
+ while (str_idx > 0)
+ {
+ /* Update counters. */
+ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
+ if (null_cnt > mctx->max_mb_elem_len)
+ {
+ memset (sctx->sifted_states, '\0',
+ sizeof (re_dfastate_t *) * str_idx);
+ re_node_set_free (&cur_dest);
+ return REG_NOERROR;
+ }
+ re_node_set_empty (&cur_dest);
+ --str_idx;
+
+ if (mctx->state_log[str_idx])
+ {
+ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* Add all the nodes which satisfy the following conditions:
+ - It can epsilon transit to a node in CUR_DEST.
+ - It is in CUR_SRC.
+ And update state_log. */
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ err = REG_NOERROR;
+ free_return:
+ re_node_set_free (&cur_dest);
+ return err;
+}
+
+static reg_errcode_t
+internal_function
+build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, re_node_set *cur_dest)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
+ int i;
+
+ /* Then build the next sifted state.
+ We build the next sifted state on `cur_dest', and update
+ `sifted_states[str_idx]' with `cur_dest'.
+ Note:
+ `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
+ `cur_src' points the node_set of the old `state_log[str_idx]'
+ (with the epsilon nodes pre-filtered out). */
+ for (i = 0; i < cur_src->nelem; i++)
+ {
+ int prev_node = cur_src->elems[i];
+ int naccepted = 0;
+ int ret;
+
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[prev_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[prev_node].accept_mb)
+ naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
+ str_idx, sctx->last_str_idx);
+#endif /* RE_ENABLE_I18N */
+
+ /* We don't check backreferences here.
+ See update_cur_sifted_state(). */
+ if (!naccepted
+ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
+ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
+ dfa->nexts[prev_node]))
+ naccepted = 1;
+
+ if (naccepted == 0)
+ continue;
+
+ if (sctx->limits.nelem)
+ {
+ int to_idx = str_idx + naccepted;
+ if (check_dst_limits (mctx, &sctx->limits,
+ dfa->nexts[prev_node], to_idx,
+ prev_node, str_idx))
+ continue;
+ }
+ ret = re_node_set_insert (cur_dest, prev_node);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions. */
+
+static reg_errcode_t
+internal_function
+clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
+{
+ int top = mctx->state_log_top;
+
+ if (next_state_log_idx >= mctx->input.bufs_len
+ || (next_state_log_idx >= mctx->input.valid_len
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ reg_errcode_t err;
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (top < next_state_log_idx)
+ {
+ memset (mctx->state_log + top + 1, '\0',
+ sizeof (re_dfastate_t *) * (next_state_log_idx - top));
+ mctx->state_log_top = next_state_log_idx;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+{
+ int st_idx;
+ reg_errcode_t err;
+ for (st_idx = 0; st_idx < num; ++st_idx)
+ {
+ if (dst[st_idx] == NULL)
+ dst[st_idx] = src[st_idx];
+ else if (src[st_idx] != NULL)
+ {
+ re_node_set merged_set;
+ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
+ &src[st_idx]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
+ re_node_set_free (&merged_set);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *dest_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ const re_node_set *candidates;
+ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
+ : &mctx->state_log[str_idx]->nodes);
+
+ if (dest_nodes->nelem == 0)
+ sctx->sifted_states[str_idx] = NULL;
+ else
+ {
+ if (candidates)
+ {
+ /* At first, add the nodes which can epsilon transit to a node in
+ DEST_NODE. */
+ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Then, check the limitations in the current sift_context. */
+ if (sctx->limits.nelem)
+ {
+ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
+ mctx->bkref_ents, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+
+ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (candidates && mctx->state_log[str_idx]->has_backref)
+ {
+ err = sift_states_bkref (mctx, sctx, str_idx, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ reg_errcode_t err = REG_NOERROR;
+ int i;
+
+ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (!state->inveclosure.alloc)
+ {
+ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < dest_nodes->nelem; i++)
+ re_node_set_merge (&state->inveclosure,
+ dfa->inveclosures + dest_nodes->elems[i]);
+ }
+ return re_node_set_add_intersect (dest_nodes, candidates,
+ &state->inveclosure);
+}
+
+static reg_errcode_t
+internal_function
+sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ int ecl_idx;
+ reg_errcode_t err;
+ re_node_set *inv_eclosure = dfa->inveclosures + node;
+ re_node_set except_nodes;
+ re_node_set_init_empty (&except_nodes);
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (cur_node == node)
+ continue;
+ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
+ {
+ int edst1 = dfa->edests[cur_node].elems[0];
+ int edst2 = ((dfa->edests[cur_node].nelem > 1)
+ ? dfa->edests[cur_node].elems[1] : -1);
+ if ((!re_node_set_contains (inv_eclosure, edst1)
+ && re_node_set_contains (dest_nodes, edst1))
+ || (edst2 > 0
+ && !re_node_set_contains (inv_eclosure, edst2)
+ && re_node_set_contains (dest_nodes, edst2)))
+ {
+ err = re_node_set_add_intersect (&except_nodes, candidates,
+ dfa->inveclosures + cur_node);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&except_nodes);
+ return err;
+ }
+ }
+ }
+ }
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (!re_node_set_contains (&except_nodes, cur_node))
+ {
+ int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
+ re_node_set_remove_at (dest_nodes, idx);
+ }
+ }
+ re_node_set_free (&except_nodes);
+ return REG_NOERROR;
+}
+
+static int
+internal_function
+check_dst_limits (const re_match_context_t *mctx, re_node_set *limits,
+ int dst_node, int dst_idx, int src_node, int src_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int lim_idx, src_pos, dst_pos;
+
+ int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
+ int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = mctx->bkref_ents + limits->elems[lim_idx];
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+
+ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, dst_node, dst_idx,
+ dst_bkref_idx);
+ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, src_node, src_idx,
+ src_bkref_idx);
+
+ /* In case of:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ if (src_pos == dst_pos)
+ continue; /* This is unrelated limitation. */
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
+ int subexp_idx, int from_node, int bkref_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *eclosures = dfa->eclosures + from_node;
+ int node_idx;
+
+ /* Else, we are on the boundary: examine the nodes on the epsilon
+ closure. */
+ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
+ {
+ int node = eclosures->elems[node_idx];
+ switch (dfa->nodes[node].type)
+ {
+ case OP_BACK_REF:
+ if (bkref_idx != -1)
+ {
+ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
+ do
+ {
+ int dst, cpos;
+
+ if (ent->node != node)
+ continue;
+
+ if (subexp_idx < BITSET_WORD_BITS
+ && !(ent->eps_reachable_subexps_map
+ & ((bitset_word_t) 1 << subexp_idx)))
+ continue;
+
+ /* Recurse trying to reach the OP_OPEN_SUBEXP and
+ OP_CLOSE_SUBEXP cases below. But, if the
+ destination node is the same node as the source
+ node, don't recurse because it would cause an
+ infinite loop: a regex that exhibits this behavior
+ is ()\1*\1* */
+ dst = dfa->edests[node].elems[0];
+ if (dst == from_node)
+ {
+ if (boundaries & 1)
+ return -1;
+ else /* if (boundaries & 2) */
+ return 0;
+ }
+
+ cpos =
+ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ dst, bkref_idx);
+ if (cpos == -1 /* && (boundaries & 1) */)
+ return -1;
+ if (cpos == 0 && (boundaries & 2))
+ return 0;
+
+ if (subexp_idx < BITSET_WORD_BITS)
+ ent->eps_reachable_subexps_map
+ &= ~((bitset_word_t) 1 << subexp_idx);
+ }
+ while (ent++->more);
+ }
+ break;
+
+ case OP_OPEN_SUBEXP:
+ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
+ return -1;
+ break;
+
+ case OP_CLOSE_SUBEXP:
+ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (boundaries & 2) ? 1 : 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit,
+ int subexp_idx, int from_node, int str_idx,
+ int bkref_idx)
+{
+ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
+ int boundaries;
+
+ /* If we are outside the range of the subexpression, return -1 or 1. */
+ if (str_idx < lim->subexp_from)
+ return -1;
+
+ if (lim->subexp_to < str_idx)
+ return 1;
+
+ /* If we are within the subexpression, return 0. */
+ boundaries = (str_idx == lim->subexp_from);
+ boundaries |= (str_idx == lim->subexp_to) << 1;
+ if (boundaries == 0)
+ return 0;
+
+ /* Else, examine epsilon closure. */
+ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ from_node, bkref_idx);
+}
+
+/* Check the limitations of sub expressions LIMITS, and remove the nodes
+ which are against limitations from DEST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates, re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents, int str_idx)
+{
+ reg_errcode_t err;
+ int node_idx, lim_idx;
+
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = bkref_ents + limits->elems[lim_idx];
+
+ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
+ continue; /* This is unrelated limitation. */
+
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+ if (ent->subexp_to == str_idx)
+ {
+ int ops_node = -1;
+ int cls_node = -1;
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_OPEN_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ ops_node = node;
+ else if (type == OP_CLOSE_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ cls_node = node;
+ }
+
+ /* Check the limitation of the open subexpression. */
+ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
+ if (ops_node >= 0)
+ {
+ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Check the limitation of the close subexpression. */
+ if (cls_node >= 0)
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ if (!re_node_set_contains (dfa->inveclosures + node,
+ cls_node)
+ && !re_node_set_contains (dfa->eclosures + node,
+ cls_node))
+ {
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ --node_idx;
+ }
+ }
+ }
+ else /* (ent->subexp_to != str_idx) */
+ {
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
+ {
+ if (subexp_idx != dfa->nodes[node].opr.idx)
+ continue;
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int node_idx, node;
+ re_sift_context_t local_sctx;
+ int first_idx = search_cur_bkref_entry (mctx, str_idx);
+
+ if (first_idx == -1)
+ return REG_NOERROR;
+
+ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
+
+ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
+ {
+ int enabled_idx;
+ re_token_type_t type;
+ struct re_backref_cache_entry *entry;
+ node = candidates->elems[node_idx];
+ type = dfa->nodes[node].type;
+ /* Avoid infinite loop for the REs like "()\1+". */
+ if (node == sctx->last_node && str_idx == sctx->last_str_idx)
+ continue;
+ if (type != OP_BACK_REF)
+ continue;
+
+ entry = mctx->bkref_ents + first_idx;
+ enabled_idx = first_idx;
+ do
+ {
+ int subexp_len;
+ int to_idx;
+ int dst_node;
+ int ret;
+ re_dfastate_t *cur_state;
+
+ if (entry->node != node)
+ continue;
+ subexp_len = entry->subexp_to - entry->subexp_from;
+ to_idx = str_idx + subexp_len;
+ dst_node = (subexp_len ? dfa->nexts[node]
+ : dfa->edests[node].elems[0]);
+
+ if (to_idx > sctx->last_str_idx
+ || sctx->sifted_states[to_idx] == NULL
+ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
+ || check_dst_limits (mctx, &sctx->limits, node,
+ str_idx, dst_node, to_idx))
+ continue;
+
+ if (local_sctx.sifted_states == NULL)
+ {
+ local_sctx = *sctx;
+ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.last_node = node;
+ local_sctx.last_str_idx = str_idx;
+ ret = re_node_set_insert (&local_sctx.limits, enabled_idx);
+ if (BE (ret < 0, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ cur_state = local_sctx.sifted_states[str_idx];
+ err = sift_states_backward (mctx, &local_sctx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ if (sctx->limited_states != NULL)
+ {
+ err = merge_state_array (dfa, sctx->limited_states,
+ local_sctx.sifted_states,
+ str_idx + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.sifted_states[str_idx] = cur_state;
+ re_node_set_remove (&local_sctx.limits, enabled_idx);
+
+ /* mctx->bkref_ents may have changed, reload the pointer. */
+ entry = mctx->bkref_ents + enabled_idx;
+ }
+ while (enabled_idx++, entry++->more);
+ }
+ err = REG_NOERROR;
+ free_return:
+ if (local_sctx.sifted_states != NULL)
+ {
+ re_node_set_free (&local_sctx.limits);
+ }
+
+ return err;
+}
+
+
+#ifdef RE_ENABLE_I18N
+static int
+internal_function
+sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int naccepted;
+ /* Check the node can accept `multi byte'. */
+ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
+ if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
+ !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
+ dfa->nexts[node_idx]))
+ /* The node can't accept the `multi byte', or the
+ destination was already thrown away, then the node
+ could't accept the current input `multi byte'. */
+ naccepted = 0;
+ /* Otherwise, it is sure that the node could accept
+ `naccepted' bytes input. */
+ return naccepted;
+}
+#endif /* RE_ENABLE_I18N */
+
+
+/* Functions for state transition. */
+
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte, and update STATE_LOG if necessary.
+ If STATE can accept a multibyte char/collating element/back reference
+ update the destination of STATE_LOG. */
+
+static re_dfastate_t *
+internal_function
+transit_state (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ re_dfastate_t **trtable;
+ unsigned char ch;
+
+#ifdef RE_ENABLE_I18N
+ /* If the current state can accept multibyte. */
+ if (BE (state->accept_mb, 0))
+ {
+ *err = transit_state_mb (mctx, state);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ /* Then decide the next state with the single byte. */
+#if 0
+ if (0)
+ /* don't use transition table */
+ return transit_state_sb (err, mctx, state);
+#endif
+
+ /* Use transition table */
+ ch = re_string_fetch_byte (&mctx->input);
+ for (;;)
+ {
+ trtable = state->trtable;
+ if (BE (trtable != NULL, 1))
+ return trtable[ch];
+
+ trtable = state->word_trtable;
+ if (BE (trtable != NULL, 1))
+ {
+ unsigned int context;
+ context
+ = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return trtable[ch + SBC_MAX];
+ else
+ return trtable[ch];
+ }
+
+ if (!build_trtable (mctx->dfa, state))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ /* Retry, we now have a transition table. */
+ }
+}
+
+/* Update the state_log if we need */
+re_dfastate_t *
+internal_function
+merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int cur_idx = re_string_cur_idx (&mctx->input);
+
+ if (cur_idx > mctx->state_log_top)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ mctx->state_log_top = cur_idx;
+ }
+ else if (mctx->state_log[cur_idx] == 0)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ }
+ else
+ {
+ re_dfastate_t *pstate;
+ unsigned int context;
+ re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
+ /* If (state_log[cur_idx] != 0), it implies that cur_idx is
+ the destination of a multibyte char/collating element/
+ back reference. Then the next state is the union set of
+ these destinations and the results of the transition table. */
+ pstate = mctx->state_log[cur_idx];
+ log_nodes = pstate->entrance_nodes;
+ if (next_state != NULL)
+ {
+ table_nodes = next_state->entrance_nodes;
+ *err = re_node_set_init_union (&next_nodes, table_nodes,
+ log_nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ else
+ next_nodes = *log_nodes;
+ /* Note: We already add the nodes of the initial state,
+ then we don't need to add them here. */
+
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ next_state = mctx->state_log[cur_idx]
+ = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ if (table_nodes != NULL)
+ re_node_set_free (&next_nodes);
+ }
+
+ if (BE (dfa->nbackref, 0) && next_state != NULL)
+ {
+ /* Check OP_OPEN_SUBEXP in the current state in case that we use them
+ later. We must check them here, since the back references in the
+ next state might use them. */
+ *err = check_subexp_matching_top (mctx, &next_state->nodes,
+ cur_idx);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+
+ /* If the next state has back references. */
+ if (next_state->has_backref)
+ {
+ *err = transit_state_bkref (mctx, &next_state->nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ next_state = mctx->state_log[cur_idx];
+ }
+ }
+
+ return next_state;
+}
+
+/* Skip bytes in the input that correspond to part of a
+ multi-byte match, then look in the log for a state
+ from which to restart matching. */
+re_dfastate_t *
+internal_function
+find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
+{
+ re_dfastate_t *cur_state;
+ do
+ {
+ int max = mctx->state_log_top;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ do
+ {
+ if (++cur_str_idx > max)
+ return NULL;
+ re_string_skip_bytes (&mctx->input, 1);
+ }
+ while (mctx->state_log[cur_str_idx] == NULL);
+
+ cur_state = merge_state_with_log (err, mctx, NULL);
+ }
+ while (*err == REG_NOERROR && cur_state == NULL);
+ return cur_state;
+}
+
+/* Helper functions for transit_state. */
+
+/* From the node set CUR_NODES, pick up the nodes whose types are
+ OP_OPEN_SUBEXP and which have corresponding back references in the regular
+ expression. And register them to use them later for evaluating the
+ correspoding back references. */
+
+static reg_errcode_t
+internal_function
+check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int node_idx;
+ reg_errcode_t err;
+
+ /* TODO: This isn't efficient.
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
+ {
+ int node = cur_nodes->elems[node_idx];
+ if (dfa->nodes[node].type == OP_OPEN_SUBEXP
+ && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
+ && (dfa->used_bkref_map
+ & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
+ {
+ err = match_ctx_add_subtop (mctx, node, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+#if 0
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte. */
+
+static re_dfastate_t *
+transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ re_node_set next_nodes;
+ re_dfastate_t *next_state;
+ int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
+ unsigned int context;
+
+ *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
+ {
+ int cur_node = state->nodes.elems[node_cnt];
+ if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
+ {
+ *err = re_node_set_merge (&next_nodes,
+ dfa->eclosures + dfa->nexts[cur_node]);
+ if (BE (*err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return NULL;
+ }
+ }
+ }
+ context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
+ next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ re_node_set_free (&next_nodes);
+ re_string_skip_bytes (&mctx->input, 1);
+ return next_state;
+}
+#endif
+
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t
+internal_function
+transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+
+ for (i = 0; i < pstate->nodes.nelem; ++i)
+ {
+ re_node_set dest_nodes, *new_nodes;
+ int cur_node_idx = pstate->nodes.elems[i];
+ int naccepted, dest_idx;
+ unsigned int context;
+ re_dfastate_t *dest_state;
+
+ if (!dfa->nodes[cur_node_idx].accept_mb)
+ continue;
+
+ if (dfa->nodes[cur_node_idx].constraint)
+ {
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input),
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
+ context))
+ continue;
+ }
+
+ /* How many bytes the node can accept? */
+ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
+ re_string_cur_idx (&mctx->input));
+ if (naccepted == 0)
+ continue;
+
+ /* The node can accepts `naccepted' bytes. */
+ dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
+ mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
+ : mctx->max_mb_elem_len);
+ err = clean_state_log_if_needed (mctx, dest_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+#ifdef DEBUG
+ assert (dfa->nexts[cur_node_idx] != -1);
+#endif
+ new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
+
+ dest_state = mctx->state_log[dest_idx];
+ if (dest_state == NULL)
+ dest_nodes = *new_nodes;
+ else
+ {
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes, new_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ context = re_string_context_at (&mctx->input, dest_idx - 1,
+ mctx->eflags);
+ mctx->state_log[dest_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ if (dest_state != NULL)
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+#endif /* RE_ENABLE_I18N */
+
+static reg_errcode_t
+internal_function
+transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ for (i = 0; i < nodes->nelem; ++i)
+ {
+ int dest_str_idx, prev_nelem, bkc_idx;
+ int node_idx = nodes->elems[i];
+ unsigned int context;
+ const re_token_t *node = dfa->nodes + node_idx;
+ re_node_set *new_dest_nodes;
+
+ /* Check whether `node' is a backreference or not. */
+ if (node->type != OP_BACK_REF)
+ continue;
+
+ if (node->constraint)
+ {
+ context = re_string_context_at (&mctx->input, cur_str_idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ continue;
+ }
+
+ /* `node' is a backreference.
+ Check the substring which the substring matched. */
+ bkc_idx = mctx->nbkref_ents;
+ err = get_subexp (mctx, node_idx, cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* And add the epsilon closures (which is `new_dest_nodes') of
+ the backreference to appropriate state_log. */
+#ifdef DEBUG
+ assert (dfa->nexts[node_idx] != -1);
+#endif
+ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
+ {
+ int subexp_len;
+ re_dfastate_t *dest_state;
+ struct re_backref_cache_entry *bkref_ent;
+ bkref_ent = mctx->bkref_ents + bkc_idx;
+ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
+ continue;
+ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
+ new_dest_nodes = (subexp_len == 0
+ ? dfa->eclosures + dfa->edests[node_idx].elems[0]
+ : dfa->eclosures + dfa->nexts[node_idx]);
+ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
+ - bkref_ent->subexp_from);
+ context = re_string_context_at (&mctx->input, dest_str_idx - 1,
+ mctx->eflags);
+ dest_state = mctx->state_log[dest_str_idx];
+ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
+ : mctx->state_log[cur_str_idx]->nodes.nelem);
+ /* Add `new_dest_node' to state_log. */
+ if (dest_state == NULL)
+ {
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, new_dest_nodes,
+ context);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ re_node_set dest_nodes;
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes,
+ new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&dest_nodes);
+ goto free_return;
+ }
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ /* We need to check recursively if the backreference can epsilon
+ transit. */
+ if (subexp_len == 0
+ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
+ {
+ err = check_subexp_matching_top (mctx, new_dest_nodes,
+ cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ err = transit_state_bkref (mctx, new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ }
+ }
+ err = REG_NOERROR;
+ free_return:
+ return err;
+}
+
+/* Enumerate all the candidates which the backreference BKREF_NODE can match
+ at BKREF_STR_IDX, and register them by match_ctx_add_entry().
+ Note that we might collect inappropriate candidates here.
+ However, the cost of checking them strictly here is too high, then we
+ delay these checking for prune_impossible_nodes(). */
+
+static reg_errcode_t
+internal_function
+get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int subexp_num, sub_top_idx;
+ const char *buf = (const char *) re_string_get_buffer (&mctx->input);
+ /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
+ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
+ if (cache_idx != -1)
+ {
+ const struct re_backref_cache_entry *entry
+ = mctx->bkref_ents + cache_idx;
+ do
+ if (entry->node == bkref_node)
+ return REG_NOERROR; /* We already checked it. */
+ while (entry++->more);
+ }
+
+ subexp_num = dfa->nodes[bkref_node].opr.idx;
+
+ /* For each sub expression */
+ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
+ {
+ reg_errcode_t err;
+ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
+ re_sub_match_last_t *sub_last;
+ int sub_last_idx, sl_str, bkref_str_off;
+
+ if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
+ continue; /* It isn't related. */
+
+ sl_str = sub_top->str_idx;
+ bkref_str_off = bkref_str_idx;
+ /* At first, check the last node of sub expressions we already
+ evaluated. */
+ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
+ {
+ int sl_str_diff;
+ sub_last = sub_top->lasts[sub_last_idx];
+ sl_str_diff = sub_last->str_idx - sl_str;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_diff > 0)
+ {
+ if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
+ {
+ /* Not enough chars for a successful match. */
+ if (bkref_str_off + sl_str_diff > mctx->input.len)
+ break;
+
+ err = clean_state_log_if_needed (mctx,
+ bkref_str_off
+ + sl_str_diff);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
+ /* We don't need to search this sub expression any more. */
+ break;
+ }
+ bkref_str_off += sl_str_diff;
+ sl_str += sl_str_diff;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+
+ /* Reload buf, since the preceding call might have reallocated
+ the buffer. */
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (sub_last_idx < sub_top->nlasts)
+ continue;
+ if (sub_last_idx > 0)
+ ++sl_str;
+ /* Then, search for the other last nodes of the sub expression. */
+ for (; sl_str <= bkref_str_idx; ++sl_str)
+ {
+ int cls_node, sl_str_off;
+ const re_node_set *nodes;
+ sl_str_off = sl_str - sub_top->str_idx;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_off > 0)
+ {
+ if (BE (bkref_str_off >= mctx->input.valid_len, 0))
+ {
+ /* If we are at the end of the input, we cannot match. */
+ if (bkref_str_off >= mctx->input.len)
+ break;
+
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (buf [bkref_str_off++] != buf[sl_str - 1])
+ break; /* We don't need to search this sub expression
+ any more. */
+ }
+ if (mctx->state_log[sl_str] == NULL)
+ continue;
+ /* Does this state have a ')' of the sub expression? */
+ nodes = &mctx->state_log[sl_str]->nodes;
+ cls_node = find_subexp_node (dfa, nodes, subexp_num,
+ OP_CLOSE_SUBEXP);
+ if (cls_node == -1)
+ continue; /* No. */
+ if (sub_top->path == NULL)
+ {
+ sub_top->path = calloc (sizeof (state_array_t),
+ sl_str - sub_top->str_idx + 1);
+ if (sub_top->path == NULL)
+ return REG_ESPACE;
+ }
+ /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
+ in the current context? */
+ err = check_arrival (mctx, sub_top->path, sub_top->node,
+ sub_top->str_idx, cls_node, sl_str,
+ OP_CLOSE_SUBEXP);
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
+ if (BE (sub_last == NULL, 0))
+ return REG_ESPACE;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+ if (err == REG_NOMATCH)
+ continue;
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Helper functions for get_subexp(). */
+
+/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
+ If it can arrive, register the sub expression expressed with SUB_TOP
+ and SUB_LAST. */
+
+static reg_errcode_t
+internal_function
+get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last, int bkref_node, int bkref_str)
+{
+ reg_errcode_t err;
+ int to_idx;
+ /* Can the subexpression arrive the back reference? */
+ err = check_arrival (mctx, &sub_last->path, sub_last->node,
+ sub_last->str_idx, bkref_node, bkref_str,
+ OP_OPEN_SUBEXP);
+ if (err != REG_NOERROR)
+ return err;
+ err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
+ sub_last->str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
+ return clean_state_log_if_needed (mctx, to_idx);
+}
+
+/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
+ Search '(' if FL_OPEN, or search ')' otherwise.
+ TODO: This function isn't efficient...
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+
+static int
+internal_function
+find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type)
+{
+ int cls_idx;
+ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
+ {
+ int cls_node = nodes->elems[cls_idx];
+ const re_token_t *node = dfa->nodes + cls_node;
+ if (node->type == type
+ && node->opr.idx == subexp_idx)
+ return cls_node;
+ }
+ return -1;
+}
+
+/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
+ LAST_NODE at LAST_STR. We record the path onto PATH since it will be
+ heavily reused.
+ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
+
+static reg_errcode_t
+internal_function
+check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ int subexp_num, backup_cur_idx, str_idx, null_cnt;
+ re_dfastate_t *cur_state = NULL;
+ re_node_set *cur_nodes, next_nodes;
+ re_dfastate_t **backup_state_log;
+ unsigned int context;
+
+ subexp_num = dfa->nodes[top_node].opr.idx;
+ /* Extend the buffer if we need. */
+ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
+ {
+ re_dfastate_t **new_array;
+ int old_alloc = path->alloc;
+ path->alloc += last_str + mctx->max_mb_elem_len + 1;
+ new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
+ if (BE (new_array == NULL, 0))
+ {
+ path->alloc = old_alloc;
+ return REG_ESPACE;
+ }
+ path->array = new_array;
+ memset (new_array + old_alloc, '\0',
+ sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
+ }
+
+ str_idx = path->next_idx ?: top_str;
+
+ /* Temporary modify MCTX. */
+ backup_state_log = mctx->state_log;
+ backup_cur_idx = mctx->input.cur_idx;
+ mctx->state_log = path->array;
+ mctx->input.cur_idx = str_idx;
+
+ /* Setup initial node set. */
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ if (str_idx == top_str)
+ {
+ err = re_node_set_init_1 (&next_nodes, top_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ cur_state = mctx->state_log[str_idx];
+ if (cur_state && cur_state->has_backref)
+ {
+ err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ re_node_set_init_empty (&next_nodes);
+ }
+ if (str_idx == top_str || (cur_state && cur_state->has_backref))
+ {
+ if (next_nodes.nelem)
+ {
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ }
+
+ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
+ {
+ re_node_set_empty (&next_nodes);
+ if (mctx->state_log[str_idx + 1])
+ {
+ err = re_node_set_merge (&next_nodes,
+ &mctx->state_log[str_idx + 1]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ if (cur_state)
+ {
+ err = check_arrival_add_next_nodes (mctx, str_idx,
+ &cur_state->non_eps_nodes,
+ &next_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ ++str_idx;
+ if (next_nodes.nelem)
+ {
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
+ }
+ re_node_set_free (&next_nodes);
+ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
+ : &mctx->state_log[last_str]->nodes);
+ path->next_idx = str_idx;
+
+ /* Fix MCTX. */
+ mctx->state_log = backup_state_log;
+ mctx->input.cur_idx = backup_cur_idx;
+
+ /* Then check the current node set has the node LAST_NODE. */
+ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
+ return REG_NOERROR;
+
+ return REG_NOMATCH;
+}
+
+/* Helper functions for check_arrival. */
+
+/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
+ to NEXT_NODES.
+ TODO: This function is similar to the functions transit_state*(),
+ however this function has many additional works.
+ Can't we unify them? */
+
+static reg_errcode_t
+internal_function
+check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx,
+ re_node_set *cur_nodes, re_node_set *next_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int result;
+ int cur_idx;
+ reg_errcode_t err = REG_NOERROR;
+ re_node_set union_set;
+ re_node_set_init_empty (&union_set);
+ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
+ {
+ int naccepted = 0;
+ int cur_node = cur_nodes->elems[cur_idx];
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[cur_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[cur_node].accept_mb)
+ {
+ naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
+ str_idx);
+ if (naccepted > 1)
+ {
+ re_dfastate_t *dest_state;
+ int next_node = dfa->nexts[cur_node];
+ int next_idx = str_idx + naccepted;
+ dest_state = mctx->state_log[next_idx];
+ re_node_set_empty (&union_set);
+ if (dest_state)
+ {
+ err = re_node_set_merge (&union_set, &dest_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ result = re_node_set_insert (&union_set, next_node);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
+ &union_set);
+ if (BE (mctx->state_log[next_idx] == NULL
+ && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (naccepted
+ || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
+ {
+ result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ }
+ }
+ re_node_set_free (&union_set);
+ return REG_NOERROR;
+}
+
+/* For all the nodes in CUR_NODES, add the epsilon closures of them to
+ CUR_NODES, however exclude the nodes which are:
+ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
+ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
+*/
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
+ int ex_subexp, int type)
+{
+ reg_errcode_t err;
+ int idx, outside_node;
+ re_node_set new_nodes;
+#ifdef DEBUG
+ assert (cur_nodes->nelem);
+#endif
+ err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ /* Create a new node set NEW_NODES with the nodes which are epsilon
+ closures of the node in CUR_NODES. */
+
+ for (idx = 0; idx < cur_nodes->nelem; ++idx)
+ {
+ int cur_node = cur_nodes->elems[idx];
+ const re_node_set *eclosure = dfa->eclosures + cur_node;
+ outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
+ if (outside_node == -1)
+ {
+ /* There are no problematic nodes, just merge them. */
+ err = re_node_set_merge (&new_nodes, eclosure);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ /* There are problematic nodes, re-calculate incrementally. */
+ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ }
+ re_node_set_free (cur_nodes);
+ *cur_nodes = new_nodes;
+ return REG_NOERROR;
+}
+
+/* Helper function for check_arrival_expand_ecl.
+ Check incrementally the epsilon closure of TARGET, and if it isn't
+ problematic append it to DST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
+ int target, int ex_subexp, int type)
+{
+ int cur_node;
+ for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
+ {
+ int err;
+
+ if (dfa->nodes[cur_node].type == type
+ && dfa->nodes[cur_node].opr.idx == ex_subexp)
+ {
+ if (type == OP_CLOSE_SUBEXP)
+ {
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ }
+ break;
+ }
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ if (dfa->edests[cur_node].nelem == 0)
+ break;
+ if (dfa->edests[cur_node].nelem == 2)
+ {
+ err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
+ dfa->edests[cur_node].elems[1],
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ cur_node = dfa->edests[cur_node].elems[0];
+ }
+ return REG_NOERROR;
+}
+
+
+/* For all the back references in the current state, calculate the
+ destination of the back references by the appropriate entry
+ in MCTX->BKREF_ENTS. */
+
+static reg_errcode_t
+internal_function
+expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int cur_str, int subexp_num, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
+ struct re_backref_cache_entry *ent;
+
+ if (cache_idx_start == -1)
+ return REG_NOERROR;
+
+ restart:
+ ent = mctx->bkref_ents + cache_idx_start;
+ do
+ {
+ int to_idx, next_node;
+
+ /* Is this entry ENT is appropriate? */
+ if (!re_node_set_contains (cur_nodes, ent->node))
+ continue; /* No. */
+
+ to_idx = cur_str + ent->subexp_to - ent->subexp_from;
+ /* Calculate the destination of the back reference, and append it
+ to MCTX->STATE_LOG. */
+ if (to_idx == cur_str)
+ {
+ /* The backreference did epsilon transit, we must re-check all the
+ node in the current state. */
+ re_node_set new_dests;
+ reg_errcode_t err2, err3;
+ next_node = dfa->edests[ent->node].elems[0];
+ if (re_node_set_contains (cur_nodes, next_node))
+ continue;
+ err = re_node_set_init_1 (&new_dests, next_node);
+ err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
+ err3 = re_node_set_merge (cur_nodes, &new_dests);
+ re_node_set_free (&new_dests);
+ if (BE (err != REG_NOERROR || err2 != REG_NOERROR
+ || err3 != REG_NOERROR, 0))
+ {
+ err = (err != REG_NOERROR ? err
+ : (err2 != REG_NOERROR ? err2 : err3));
+ return err;
+ }
+ /* TODO: It is still inefficient... */
+ goto restart;
+ }
+ else
+ {
+ re_node_set union_set;
+ next_node = dfa->nexts[ent->node];
+ if (mctx->state_log[to_idx])
+ {
+ int ret;
+ if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
+ next_node))
+ continue;
+ err = re_node_set_init_copy (&union_set,
+ &mctx->state_log[to_idx]->nodes);
+ ret = re_node_set_insert (&union_set, next_node);
+ if (BE (err != REG_NOERROR || ret < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ err = err != REG_NOERROR ? err : REG_ESPACE;
+ return err;
+ }
+ }
+ else
+ {
+ err = re_node_set_init_1 (&union_set, next_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
+ re_node_set_free (&union_set);
+ if (BE (mctx->state_log[to_idx] == NULL
+ && err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ while (ent++->more);
+ return REG_NOERROR;
+}
+
+/* Build transition table for the state.
+ Return 1 if succeeded, otherwise return NULL. */
+
+static int
+internal_function
+build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
+{
+ reg_errcode_t err;
+ int i, j, ch, need_word_trtable = 0;
+ bitset_word_t elem, mask;
+ bool dests_node_malloced = false;
+ bool dest_states_malloced = false;
+ int ndests; /* Number of the destination states from `state'. */
+ re_dfastate_t **trtable;
+ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
+ re_node_set follows, *dests_node;
+ bitset_t *dests_ch;
+ bitset_t acceptable;
+
+ struct dests_alloc
+ {
+ re_node_set dests_node[SBC_MAX];
+ bitset_t dests_ch[SBC_MAX];
+ } *dests_alloc;
+
+ /* We build DFA states which corresponds to the destination nodes
+ from `state'. `dests_node[i]' represents the nodes which i-th
+ destination state contains, and `dests_ch[i]' represents the
+ characters which i-th destination state accepts. */
+ if (__libc_use_alloca (sizeof (struct dests_alloc)))
+ dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
+ else
+ {
+ dests_alloc = re_malloc (struct dests_alloc, 1);
+ if (BE (dests_alloc == NULL, 0))
+ return 0;
+ dests_node_malloced = true;
+ }
+ dests_node = dests_alloc->dests_node;
+ dests_ch = dests_alloc->dests_ch;
+
+ /* Initialize transiton table. */
+ state->word_trtable = state->trtable = NULL;
+
+ /* At first, group all nodes belonging to `state' into several
+ destinations. */
+ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
+ if (BE (ndests <= 0, 0))
+ {
+ if (dests_node_malloced)
+ free (dests_alloc);
+ /* Return 0 in case of an error, 1 otherwise. */
+ if (ndests == 0)
+ {
+ state->trtable = (re_dfastate_t **)
+ calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ return 1;
+ }
+ return 0;
+ }
+
+ err = re_node_set_alloc (&follows, ndests + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
+ + ndests * 3 * sizeof (re_dfastate_t *)))
+ dest_states = (re_dfastate_t **)
+ alloca (ndests * 3 * sizeof (re_dfastate_t *));
+ else
+ {
+ dest_states = (re_dfastate_t **)
+ malloc (ndests * 3 * sizeof (re_dfastate_t *));
+ if (BE (dest_states == NULL, 0))
+ {
+out_free:
+ if (dest_states_malloced)
+ free (dest_states);
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+ if (dests_node_malloced)
+ free (dests_alloc);
+ return 0;
+ }
+ dest_states_malloced = true;
+ }
+ dest_states_word = dest_states + ndests;
+ dest_states_nl = dest_states_word + ndests;
+ bitset_empty (acceptable);
+
+ /* Then build the states for all destinations. */
+ for (i = 0; i < ndests; ++i)
+ {
+ int next_node;
+ re_node_set_empty (&follows);
+ /* Merge the follows of this destination states. */
+ for (j = 0; j < dests_node[i].nelem; ++j)
+ {
+ next_node = dfa->nexts[dests_node[i].elems[j]];
+ if (next_node != -1)
+ {
+ err = re_node_set_merge (&follows, dfa->eclosures + next_node);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ }
+ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
+ if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ /* If the new state has context constraint,
+ build appropriate states for these contexts. */
+ if (dest_states[i]->has_constraint)
+ {
+ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_WORD);
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_NEWLINE);
+ if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ else
+ {
+ dest_states_word[i] = dest_states[i];
+ dest_states_nl[i] = dest_states[i];
+ }
+ bitset_merge (acceptable, dests_ch[i]);
+ }
+
+ if (!BE (need_word_trtable, 0))
+ {
+ /* We don't care about whether the following character is a word
+ character, or we are in a single-byte character set so we can
+ discern by looking at the character code: allocate a
+ 256-entry transition table. */
+ trtable = state->trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ if (dfa->word_char[i] & mask)
+ trtable[ch] = dest_states_word[j];
+ else
+ trtable[ch] = dest_states[j];
+ }
+ }
+ else
+ {
+ /* We care about whether the following character is a word
+ character, and we are in a multi-byte character set: discern
+ by looking at the character code: build two 256-entry
+ transition tables, one starting at trtable[0] and one
+ starting at trtable[SBC_MAX]. */
+ trtable = state->word_trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ trtable[ch] = dest_states[j];
+ trtable[ch + SBC_MAX] = dest_states_word[j];
+ }
+ }
+
+ /* new line */
+ if (bitset_contain (acceptable, NEWLINE_CHAR))
+ {
+ /* The current state accepts newline character. */
+ for (j = 0; j < ndests; ++j)
+ if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
+ {
+ /* k-th destination accepts newline character. */
+ trtable[NEWLINE_CHAR] = dest_states_nl[j];
+ if (need_word_trtable)
+ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
+ /* There must be only one destination which accepts
+ newline. See group_nodes_into_DFAstates. */
+ break;
+ }
+ }
+
+ if (dest_states_malloced)
+ free (dest_states);
+
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+
+ if (dests_node_malloced)
+ free (dests_alloc);
+
+ return 1;
+}
+
+/* Group all nodes belonging to STATE into several destinations.
+ Then for all destinations, set the nodes belonging to the destination
+ to DESTS_NODE[i] and set the characters accepted by the destination
+ to DEST_CH[i]. This function return the number of destinations. */
+
+static int
+internal_function
+group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
+ re_node_set *dests_node, bitset_t *dests_ch)
+{
+ reg_errcode_t err;
+ int result;
+ int i, j, k;
+ int ndests; /* Number of the destinations from `state'. */
+ bitset_t accepts; /* Characters a node can accept. */
+ const re_node_set *cur_nodes = &state->nodes;
+ bitset_empty (accepts);
+ ndests = 0;
+
+ /* For all the nodes belonging to `state', */
+ for (i = 0; i < cur_nodes->nelem; ++i)
+ {
+ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
+ re_token_type_t type = node->type;
+ unsigned int constraint = node->constraint;
+
+ /* Enumerate all single byte character this node can accept. */
+ if (type == CHARACTER)
+ bitset_set (accepts, node->opr.c);
+ else if (type == SIMPLE_BRACKET)
+ {
+ bitset_merge (accepts, node->opr.sbcset);
+ }
+ else if (type == OP_PERIOD)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+#endif
+ bitset_set_all (accepts);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == OP_UTF8_PERIOD)
+ {
+ memset (accepts, '\xff', sizeof (bitset_t) / 2);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#endif
+ else
+ continue;
+
+ /* Check the `accepts' and sift the characters which are not
+ match it the context. */
+ if (constraint)
+ {
+ if (constraint & NEXT_NEWLINE_CONSTRAINT)
+ {
+ bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
+ bitset_empty (accepts);
+ if (accepts_newline)
+ bitset_set (accepts, NEWLINE_CHAR);
+ else
+ continue;
+ }
+ if (constraint & NEXT_ENDBUF_CONSTRAINT)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+
+ if (constraint & NEXT_WORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && !node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ if (constraint & NEXT_NOTWORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ }
+
+ /* Then divide `accepts' into DFA states, or create a new
+ state. Above, we make sure that accepts is not empty. */
+ for (j = 0; j < ndests; ++j)
+ {
+ bitset_t intersec; /* Intersection sets, see below. */
+ bitset_t remains;
+ /* Flags, see below. */
+ bitset_word_t has_intersec, not_subset, not_consumed;
+
+ /* Optimization, skip if this state doesn't accept the character. */
+ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
+ continue;
+
+ /* Enumerate the intersection set of this state and `accepts'. */
+ has_intersec = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
+ /* And skip if the intersection set is empty. */
+ if (!has_intersec)
+ continue;
+
+ /* Then check if this state is a subset of `accepts'. */
+ not_subset = not_consumed = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ {
+ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
+ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
+ }
+
+ /* If this state isn't a subset of `accepts', create a
+ new group state, which has the `remains'. */
+ if (not_subset)
+ {
+ bitset_copy (dests_ch[ndests], remains);
+ bitset_copy (dests_ch[j], intersec);
+ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ }
+
+ /* Put the position in the current group. */
+ result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
+ if (BE (result < 0, 0))
+ goto error_return;
+
+ /* If all characters are consumed, go to next node. */
+ if (!not_consumed)
+ break;
+ }
+ /* Some characters remain, create a new group. */
+ if (j == ndests)
+ {
+ bitset_copy (dests_ch[ndests], accepts);
+ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ bitset_empty (accepts);
+ }
+ }
+ return ndests;
+ error_return:
+ for (j = 0; j < ndests; ++j)
+ re_node_set_free (dests_node + j);
+ return -1;
+}
+
+#ifdef RE_ENABLE_I18N
+/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
+ Return the number of the bytes the node accepts.
+ STR_IDX is the current index of the input string.
+
+ This function handles the nodes which can accept one character, or
+ one collating element like '.', '[a-z]', opposite to the other nodes
+ can only accept one byte. */
+
+static int
+internal_function
+check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int str_idx)
+{
+ const re_token_t *node = dfa->nodes + node_idx;
+ int char_len, elem_len;
+ int i;
+
+ if (BE (node->type == OP_UTF8_PERIOD, 0))
+ {
+ unsigned char c = re_string_byte_at (input, str_idx), d;
+ if (BE (c < 0xc2, 1))
+ return 0;
+
+ if (str_idx + 2 > input->len)
+ return 0;
+
+ d = re_string_byte_at (input, str_idx + 1);
+ if (c < 0xe0)
+ return (d < 0x80 || d > 0xbf) ? 0 : 2;
+ else if (c < 0xf0)
+ {
+ char_len = 3;
+ if (c == 0xe0 && d < 0xa0)
+ return 0;
+ }
+ else if (c < 0xf8)
+ {
+ char_len = 4;
+ if (c == 0xf0 && d < 0x90)
+ return 0;
+ }
+ else if (c < 0xfc)
+ {
+ char_len = 5;
+ if (c == 0xf8 && d < 0x88)
+ return 0;
+ }
+ else if (c < 0xfe)
+ {
+ char_len = 6;
+ if (c == 0xfc && d < 0x84)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (str_idx + char_len > input->len)
+ return 0;
+
+ for (i = 1; i < char_len; ++i)
+ {
+ d = re_string_byte_at (input, str_idx + i);
+ if (d < 0x80 || d > 0xbf)
+ return 0;
+ }
+ return char_len;
+ }
+
+ char_len = re_string_char_size_at (input, str_idx);
+ if (node->type == OP_PERIOD)
+ {
+ if (char_len <= 1)
+ return 0;
+ /* FIXME: I don't think this if is needed, as both '\n'
+ and '\0' are char_len == 1. */
+ /* '.' accepts any one character except the following two cases. */
+ if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
+ re_string_byte_at (input, str_idx) == '\n') ||
+ ((dfa->syntax & RE_DOT_NOT_NULL) &&
+ re_string_byte_at (input, str_idx) == '\0'))
+ return 0;
+ return char_len;
+ }
+
+ elem_len = re_string_elem_size_at (input, str_idx);
+ if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
+ return 0;
+
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+# ifdef _LIBC
+ const unsigned char *pin
+ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+ int j;
+ uint32_t nrules;
+# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+
+ /* match with multibyte character? */
+ for (i = 0; i < cset->nmbchars; ++i)
+ if (wc == cset->mbchars[i])
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+ wctype_t wt = cset->char_classes[i];
+ if (__iswctype (wc, wt))
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ unsigned int in_collseq = 0;
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra;
+ const char *collseqwc;
+ int32_t idx;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+
+ /* match with collating_symbol? */
+ if (cset->ncoll_syms)
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ for (i = 0; i < cset->ncoll_syms; ++i)
+ {
+ const unsigned char *coll_sym = extra + cset->coll_syms[i];
+ /* Compare the length of input collating element and
+ the length of current collating element. */
+ if (*coll_sym != elem_len)
+ continue;
+ /* Compare each bytes. */
+ for (j = 0; j < *coll_sym; j++)
+ if (pin[j] != coll_sym[1 + j])
+ break;
+ if (j == *coll_sym)
+ {
+ /* Match if every bytes is equal. */
+ match_len = j;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+ if (cset->nranges)
+ {
+ if (elem_len <= char_len)
+ {
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ in_collseq = __collseq_table_lookup (collseqwc, wc);
+ }
+ else
+ in_collseq = find_collation_sequence_value (pin, elem_len);
+ }
+ /* match with range expression? */
+ for (i = 0; i < cset->nranges; ++i)
+ if (cset->range_starts[i] <= in_collseq
+ && in_collseq <= cset->range_ends[i])
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+
+ /* match with equivalence_class? */
+ if (cset->nequiv_classes)
+ {
+ const unsigned char *cp = pin;
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+ idx = findidx (&cp);
+ if (idx > 0)
+ for (i = 0; i < cset->nequiv_classes; ++i)
+ {
+ int32_t equiv_class_idx = cset->equiv_classes[i];
+ size_t weight_len = weights[idx];
+ if (weight_len == weights[equiv_class_idx])
+ {
+ int cnt = 0;
+ while (cnt <= weight_len
+ && (weights[equiv_class_idx + 1 + cnt]
+ == weights[idx + 1 + cnt]))
+ ++cnt;
+ if (cnt > weight_len)
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ }
+ }
+ else
+# endif /* _LIBC */
+ {
+ /* match with range expression? */
+#if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+#else
+ wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+ cmp_buf[2] = wc;
+#endif
+ for (i = 0; i < cset->nranges; ++i)
+ {
+ cmp_buf[0] = cset->range_starts[i];
+ cmp_buf[4] = cset->range_ends[i];
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+ return match_len;
+ else
+ {
+ if (match_len > 0)
+ return 0;
+ else
+ return (elem_len > char_len) ? elem_len : char_len;
+ }
+ }
+ return 0;
+}
+
+# ifdef _LIBC
+static unsigned int
+internal_function
+find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+{
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules == 0)
+ {
+ if (mbs_len == 1)
+ {
+ /* No valid character. Match it as a single byte character. */
+ const unsigned char *collseq = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ return collseq[mbs[0]];
+ }
+ return UINT_MAX;
+ }
+ else
+ {
+ int32_t idx;
+ const unsigned char *extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ int32_t extrasize = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
+
+ for (idx = 0; idx < extrasize;)
+ {
+ int mbs_cnt, found = 0;
+ int32_t elem_mbs_len;
+ /* Skip the name of collating element name. */
+ idx = idx + extra[idx] + 1;
+ elem_mbs_len = extra[idx++];
+ if (mbs_len == elem_mbs_len)
+ {
+ for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
+ if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
+ break;
+ if (mbs_cnt == elem_mbs_len)
+ /* Found the entry. */
+ found = 1;
+ }
+ /* Skip the byte sequence of the collating element. */
+ idx += elem_mbs_len;
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ /* Skip the wide char sequence of the collating element. */
+ idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
+ /* If we found the entry, return the sequence value. */
+ if (found)
+ return *(uint32_t *) (extra + idx);
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ }
+ return UINT_MAX;
+ }
+}
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+
+/* Check whether the node accepts the byte which is IDX-th
+ byte of the INPUT. */
+
+static int
+internal_function
+check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
+ int idx)
+{
+ unsigned char ch;
+ ch = re_string_byte_at (&mctx->input, idx);
+ switch (node->type)
+ {
+ case CHARACTER:
+ if (node->opr.c != ch)
+ return 0;
+ break;
+
+ case SIMPLE_BRACKET:
+ if (!bitset_contain (node->opr.sbcset, ch))
+ return 0;
+ break;
+
+#ifdef RE_ENABLE_I18N
+ case OP_UTF8_PERIOD:
+ if (ch >= 0x80)
+ return 0;
+ /* FALLTHROUGH */
+#endif
+ case OP_PERIOD:
+ if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
+ || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (node->constraint)
+ {
+ /* The node has constraints. Check whether the current context
+ satisfies the constraints. */
+ unsigned int context = re_string_context_at (&mctx->input, idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Extend the buffers, if the buffers have run out. */
+
+static reg_errcode_t
+internal_function
+extend_buffers (re_match_context_t *mctx)
+{
+ reg_errcode_t ret;
+ re_string_t *pstr = &mctx->input;
+
+ /* Double the lengthes of the buffers. */
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ if (mctx->state_log != NULL)
+ {
+ /* And double the length of state_log. */
+ /* XXX We have no indication of the size of this buffer. If this
+ allocation fail we have no indication that the state_log array
+ does not have the right size. */
+ re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
+ pstr->bufs_len + 1);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->state_log = new_array;
+ }
+
+ /* Then reconstruct the buffers. */
+ if (pstr->icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ }
+ return REG_NOERROR;
+}
+
+
+/* Functions for matching context. */
+
+/* Initialize MCTX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_init (re_match_context_t *mctx, int eflags, int n)
+{
+ mctx->eflags = eflags;
+ mctx->match_last = -1;
+ if (n > 0)
+ {
+ mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
+ mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
+ if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
+ return REG_ESPACE;
+ }
+ /* Already zero-ed by the caller.
+ else
+ mctx->bkref_ents = NULL;
+ mctx->nbkref_ents = 0;
+ mctx->nsub_tops = 0; */
+ mctx->abkref_ents = n;
+ mctx->max_mb_elem_len = 1;
+ mctx->asub_tops = n;
+ return REG_NOERROR;
+}
+
+/* Clean the entries which depend on the current input in MCTX.
+ This function must be invoked when the matcher changes the start index
+ of the input, or changes the input string. */
+
+static void
+internal_function
+match_ctx_clean (re_match_context_t *mctx)
+{
+ int st_idx;
+ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
+ {
+ int sl_idx;
+ re_sub_match_top_t *top = mctx->sub_tops[st_idx];
+ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
+ {
+ re_sub_match_last_t *last = top->lasts[sl_idx];
+ re_free (last->path.array);
+ re_free (last);
+ }
+ re_free (top->lasts);
+ if (top->path)
+ {
+ re_free (top->path->array);
+ re_free (top->path);
+ }
+ free (top);
+ }
+
+ mctx->nsub_tops = 0;
+ mctx->nbkref_ents = 0;
+}
+
+/* Free all the memory associated with MCTX. */
+
+static void
+internal_function
+match_ctx_free (re_match_context_t *mctx)
+{
+ /* First, free all the memory associated with MCTX->SUB_TOPS. */
+ match_ctx_clean (mctx);
+ re_free (mctx->sub_tops);
+ re_free (mctx->bkref_ents);
+}
+
+/* Add a new backreference entry to MCTX.
+ Note that we assume that caller never call this function with duplicate
+ entry, and call with STR_IDX which isn't smaller than any existing entry.
+*/
+
+static reg_errcode_t
+internal_function
+match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from,
+ int to)
+{
+ if (mctx->nbkref_ents >= mctx->abkref_ents)
+ {
+ struct re_backref_cache_entry* new_entry;
+ new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
+ mctx->abkref_ents * 2);
+ if (BE (new_entry == NULL, 0))
+ {
+ re_free (mctx->bkref_ents);
+ return REG_ESPACE;
+ }
+ mctx->bkref_ents = new_entry;
+ memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
+ sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
+ mctx->abkref_ents *= 2;
+ }
+ if (mctx->nbkref_ents > 0
+ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
+ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
+
+ mctx->bkref_ents[mctx->nbkref_ents].node = node;
+ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
+
+ /* This is a cache that saves negative results of check_dst_limits_calc_pos.
+ If bit N is clear, means that this entry won't epsilon-transition to
+ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
+ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
+ such node.
+
+ A backreference does not epsilon-transition unless it is empty, so set
+ to all zeros if FROM != TO. */
+ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
+ = (from == to ? ~0 : 0);
+
+ mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
+ if (mctx->max_mb_elem_len < to - from)
+ mctx->max_mb_elem_len = to - from;
+ return REG_NOERROR;
+}
+
+/* Search for the first entry which has the same str_idx, or -1 if none is
+ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
+
+static int
+internal_function
+search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+{
+ int left, right, mid, last;
+ last = right = mctx->nbkref_ents;
+ for (left = 0; left < right;)
+ {
+ mid = (left + right) / 2;
+ if (mctx->bkref_ents[mid].str_idx < str_idx)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
+ return left;
+ else
+ return -1;
+}
+
+/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
+ at STR_IDX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx)
+{
+#ifdef DEBUG
+ assert (mctx->sub_tops != NULL);
+ assert (mctx->asub_tops > 0);
+#endif
+ if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
+ {
+ int new_asub_tops = mctx->asub_tops * 2;
+ re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
+ re_sub_match_top_t *,
+ new_asub_tops);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops = new_array;
+ mctx->asub_tops = new_asub_tops;
+ }
+ mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
+ if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops[mctx->nsub_tops]->node = node;
+ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
+ return REG_NOERROR;
+}
+
+/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
+ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
+
+static re_sub_match_last_t *
+internal_function
+match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx)
+{
+ re_sub_match_last_t *new_entry;
+ if (BE (subtop->nlasts == subtop->alasts, 0))
+ {
+ int new_alasts = 2 * subtop->alasts + 1;
+ re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
+ re_sub_match_last_t *,
+ new_alasts);
+ if (BE (new_array == NULL, 0))
+ return NULL;
+ subtop->lasts = new_array;
+ subtop->alasts = new_alasts;
+ }
+ new_entry = calloc (1, sizeof (re_sub_match_last_t));
+ if (BE (new_entry != NULL, 1))
+ {
+ subtop->lasts[subtop->nlasts] = new_entry;
+ new_entry->node = node;
+ new_entry->str_idx = str_idx;
+ ++subtop->nlasts;
+ }
+ return new_entry;
+}
+
+static void
+internal_function
+sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node, int last_str_idx)
+{
+ sctx->sifted_states = sifted_sts;
+ sctx->limited_states = limited_sts;
+ sctx->last_node = last_node;
+ sctx->last_str_idx = last_str_idx;
+ re_node_set_init_empty (&sctx->limits);
+}
diff --git a/libc/posix/runptests.c b/libc/posix/runptests.c
new file mode 100644
index 000000000..4d43180e4
--- /dev/null
+++ b/libc/posix/runptests.c
@@ -0,0 +1,123 @@
+/* POSIX regex testsuite from IEEE 2003.2.
+ Copyright (C) 1998, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Data structure to describe the tests. */
+struct test
+{
+ int start;
+ int end;
+ const char *reg;
+ const char *str;
+ int options;
+} tests[] =
+{
+#include "ptestcases.h"
+};
+
+
+int
+main (int argc, char *argv[])
+{
+ size_t cnt;
+ int errors = 0;
+
+ for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt)
+ if (tests[cnt].str == NULL)
+ {
+ printf ("\n%s\n%.*s\n", tests[cnt].reg,
+ (int) strlen (tests[cnt].reg),
+ "-----------------------------------------------------");
+ }
+ else if (tests[cnt].reg == NULL)
+ printf ("!!! %s\n", tests[cnt].str);
+ else
+ {
+ regex_t re;
+ regmatch_t match[20];
+ int err;
+
+ printf ("regexp: \"%s\", string: \"%s\" -> ", tests[cnt].reg,
+ tests[cnt].str);
+
+ /* Compile the expression. */
+ err = regcomp (&re, tests[cnt].reg, tests[cnt].options);
+ if (err != 0)
+ {
+ if (tests[cnt].start == -2)
+ puts ("compiling failed, OK");
+ else
+ {
+ char buf[100];
+ regerror (err, &re, buf, sizeof (buf));
+ printf ("FAIL: %s\n", buf);
+ ++errors;
+ }
+
+ continue;
+ }
+ else if (tests[cnt].start == -2)
+ {
+ puts ("compiling suceeds, FAIL");
+ errors++;
+ continue;
+ }
+
+ /* Run the actual test. */
+ err = regexec (&re, tests[cnt].str, 20, match, 0);
+
+ if (err != 0)
+ {
+ if (tests[cnt].start == -1)
+ puts ("no match, OK");
+ else
+ {
+ puts ("no match, FAIL");
+ ++errors;
+ }
+ }
+ else
+ {
+ if (match[0].rm_so == 0 && tests[cnt].start == 0
+ && match[0].rm_eo == 0 && tests[cnt].end == 0)
+ puts ("match, OK");
+ else if (match[0].rm_so + 1 == tests[cnt].start
+ && match[0].rm_eo == tests[cnt].end)
+ puts ("match, OK");
+ else
+ {
+ printf ("wrong match (%d to %d): FAIL\n",
+ match[0].rm_so, match[0].rm_eo);
+ ++errors;
+ }
+ }
+
+ /* Free all resources. */
+ regfree (&re);
+ }
+
+ printf ("\n%Zu tests, %d errors\n", cnt, errors);
+
+ return errors != 0;
+}
diff --git a/libc/posix/runtests.c b/libc/posix/runtests.c
new file mode 100644
index 000000000..9d744751e
--- /dev/null
+++ b/libc/posix/runtests.c
@@ -0,0 +1,138 @@
+/***********************************************************
+
+Copyright 1995 by Tom Lord
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of the copyright holder not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+Tom Lord DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL TOM LORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+struct a_test
+{
+ int expected;
+ const char * pattern;
+ const unsigned char * data;
+};
+
+static const struct a_test the_tests[] =
+{
+#include "testcases.h"
+ {-1, 0, 0}
+};
+
+
+
+
+static int
+run_a_test (int id, const struct a_test * t)
+{
+ static const char * last_pattern = 0;
+ static regex_t r;
+ int err;
+ char errmsg[100];
+ int x;
+ regmatch_t regs[10];
+
+ if (!last_pattern || strcmp (last_pattern, t->pattern))
+ {
+ if (last_pattern)
+ regfree (&r);
+ last_pattern = t->pattern;
+ err = regcomp (&r, t->pattern, REG_EXTENDED);
+ if (err)
+ {
+ if (t->expected == 2)
+ {
+ puts (" OK.");
+ return 0;
+ }
+ if (last_pattern)
+ regfree (&r);
+ last_pattern = NULL;
+ regerror (err, &r, errmsg, 100);
+ printf (" FAIL: %s.\n", errmsg);
+ return 1;
+ }
+ else if (t->expected == 2)
+ {
+ printf ("test %d\n", id);
+ printf ("pattern \"%s\" successfull compilation not expected\n",
+ t->pattern);
+ return 1;
+ }
+ }
+
+ err = regexec (&r, t->data, 10, regs, 0);
+
+ if (err != t->expected)
+ {
+ printf ("test %d\n", id);
+ printf ("pattern \"%s\" data \"%s\" wanted %d got %d\n",
+ t->pattern, t->data, t->expected, err);
+ for (x = 0; x < 10; ++x)
+ printf ("reg %d == (%d, %d) %.*s\n",
+ x,
+ regs[x].rm_so,
+ regs[x].rm_eo,
+ regs[x].rm_eo - regs[x].rm_so,
+ t->data + regs[x].rm_so);
+ return 1;
+ }
+ puts (" OK.");
+ return 0;
+}
+
+
+
+int
+main (int argc, char * argv[])
+{
+ int x;
+ int lo;
+ int hi;
+ int res = 0;
+
+ lo = 0;
+ hi = (sizeof (the_tests) / sizeof (the_tests[0])) - 1;
+
+ if (argc > 1)
+ {
+ lo = atoi (argv[1]);
+ hi = lo + 1;
+
+ if (argc > 2)
+ hi = atoi (argv[2]);
+ }
+
+ for (x = lo; x < hi; ++x)
+ {
+ printf ("#%d:", x);
+ res |= run_a_test (x, &the_tests[x]);
+ }
+ return res != 0;
+}
diff --git a/libc/posix/rxspencer/COPYRIGHT b/libc/posix/rxspencer/COPYRIGHT
new file mode 100644
index 000000000..30c1f7a48
--- /dev/null
+++ b/libc/posix/rxspencer/COPYRIGHT
@@ -0,0 +1,20 @@
+Copyright 1992, 1993, 1994, 1997 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
diff --git a/libc/posix/rxspencer/tests b/libc/posix/rxspencer/tests
new file mode 100644
index 000000000..b84a270cd
--- /dev/null
+++ b/libc/posix/rxspencer/tests
@@ -0,0 +1,538 @@
+# regular expression test set
+# Lines are at least three fields, separated by one or more tabs. "" stands
+# for an empty field. First field is an RE. Second field is flags. If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against. If there is no fourth field, the match is
+# expected to fail. If there is a fourth field, it is the substring that
+# the RE is expected to match. If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one. In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match. The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+# - placeholder, does nothing
+# b RE is a BRE, not an ERE
+# & try it as both an ERE and a BRE
+# C regcomp() error expected, third field is error name
+# i REG_ICASE
+# m ("mundane") REG_NOSPEC
+# s REG_NOSUB (not really testable)
+# n REG_NEWLINE
+# ^ REG_NOTBOL
+# $ REG_NOTEOL
+# # REG_STARTEND (see below)
+# p REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a & a a
+abc & abc abc
+abc|de - abc abc
+a|b|c - abc a
+
+# 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) - a) a)
+) - ) )
+# 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
+
+# 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
+
+# certain syntax errors and non-errors
+| C EMPTY
+| b | |
+* C BADRPT
+* b * *
++ C BADRPT
+? C BADRPT
+"" &C EMPTY
+() - abc @abc
+\(\) b abc @abc
+a||b C EMPTY
+|ab C EMPTY
+ab| C EMPTY
+(|a)b C EMPTY
+(a|)b C EMPTY
+(*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
+
+# 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
+# The following test is wrong. Using \b in an BRE or ERE is undefined.
+# 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\
+
+# 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
+
+# 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
+
+# the dreaded bounded repetitions
+# The following two tests are not correct:
+#{ & { {
+#{abc & {abc {abc
+# '{' is always a special char outside bracket expressions. So test ony BRE:
+{ b { {
+{abc b {abc {abc
+{1 C BADRPT
+{1} C BADRPT
+# Same reason as for the two tests above:
+#a{b & a{b a{b
+a{b b a{b a{b
+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
+# These four tests checks for undefined behavior. Our implementation does
+# something different.
+#a{,2} - a{,2} a{,2}
+#a\{,2\} bC BADBR
+#a{,} - a{,} a{,}
+#a\{,\} bC BADBR
+a{1,x} C BADBR
+a\{1,x\} bC BADBR
+a{1,x C EBRACE
+a\{1,x bC EBRACE
+# These two tests probably fails due to an arbitrary limit on the number of
+# repetitions in the other implementation.
+#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
+
+# multiple repetitions
+# Wow, there is serious disconnect here. The ERE grammar is like this:
+# ERE_expression : one_char_or_coll_elem_ERE
+# | '^'
+# | '$'
+# | '(' extended_reg_exp ')'
+# | ERE_expression ERE_dupl_symbol
+# ;
+# where ERE_dupl_symbol is any of the repetition methods. It is clear from
+# this that consecutive repetition is OK. On top of this, the one test not
+# marked as failing must fail. For BREs the situation is different, so we
+# use the four tests.
+#a** &C BADRPT
+a** bC 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} - a{b} a{b}
+a\{1\}\{1\} bC BADRPT
+a*\{1\} bC BADRPT
+a\{1\}* bC BADRPT
+
+# 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
+# I don't thing the error value should be ERANGE since a[1-] would be
+# valid, too. Expect EBRACK.
+#a[1- &C ERANGE
+a[1- &C EBRACK
+a[[. &C EBRACK
+a[[.x &C EBRACK
+a[[.x. &C EBRACK
+a[[.x.] &C EBRACK
+a[[.x.]] & ax ax
+a[[.x,.]] &C ECOLLATE
+# This test is invalid. "one" is no collating symbol in any standardized
+# locale.
+# 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
+# This test is invalid. "one" is no collating symbol in any standardized
+# locale.
+#a[[=one=]]b & a1b a1b
+
+# 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
+
+# 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
+() s abc @abc
+a* & b @b
+
+# 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*/
+
+# subexpressions
+.* - abc abc -
+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 c
+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 b,-,-
+a(b+|((c)*))+d - abcd abcd c,c,c
+
+# 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
+
+# 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 EMPTY
+
+# 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
+
+# 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
+
+# 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
+a*a*a*a*a*a*a* & aaaaaa aaaaaa
+(\b){0} - x @x -
+\(\b\)\{0,0\} b abc @abc -
+a(\b){0}c - ac ac -
+a(.*)b(\1){0}c - abc abc @bc,-
+a(.*)b(\1){0}c - axbc axbc x,-
+
+a\(\(b*\)\)c\1d b abbcbbd abbcbbd bb,bb
+a\(\([bc]\)\)\2d b abcdabbd abbd b,b
+a\(\(\(\([bc]\)\)\3\)\)*d b abbccd abbccd cc,cc,c,c
+a(b)(c)d - abcd abcd b,c
+a(((b)))c - abc abc b,b,b
+a(((b|(((c))))))d - abd abd b,b,b,-,-,-
+a(((b*|c|e)))d - abbd abbd bb,bb,bb
+a((b|c)){0,0}d - ad ad -,-
+a((b|c)){0,1}d - abd abd b,b
+a((b|c)){0,2}d - abcd abcd c,c
+a((b+|((c)*)))+d - abd abd b,b,-,-
+a((b+|((c)*)))+d - abcd abcd c,c,c,c
+(((\b))){0} - x @x -,-,-
+a(((.*)))b((\2)){0}c - abc abc @bc,@bc,@bc,-,-
+a(((.*)))b((\1)){0}c - axbc axbc x,x,x,-,-
+
+\b & SaT @aT
+\b & aT @aT
+a.*\b & abT ab
+\b & STSS
+\B & abc @bc
+\B & aSbTc
+\B & SaT @SaT
+\B & aSTSb @TSb
diff --git a/libc/posix/sched.h b/libc/posix/sched.h
new file mode 100644
index 000000000..7cfdbf1f9
--- /dev/null
+++ b/libc/posix/sched.h
@@ -0,0 +1,86 @@
+/* Definitions for POSIX 1003.1b-1993 (aka POSIX.4) scheduling interface.
+ Copyright (C) 1996,1997,1999,2001-2003,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SCHED_H
+#define _SCHED_H 1
+
+#include <features.h>
+
+/* Get type definitions. */
+#include <bits/types.h>
+
+#define __need_timespec
+#include <time.h>
+
+/* Get system specific constant and data structure definitions. */
+#include <bits/sched.h>
+/* Define the real names for the elements of `struct sched_param'. */
+#define sched_priority __sched_priority
+
+
+__BEGIN_DECLS
+
+/* Set scheduling parameters for a process. */
+extern int sched_setparam (__pid_t __pid, __const struct sched_param *__param)
+ __THROW;
+
+/* Retrieve scheduling parameters for a particular process. */
+extern int sched_getparam (__pid_t __pid, struct sched_param *__param) __THROW;
+
+/* Set scheduling algorithm and/or parameters for a process. */
+extern int sched_setscheduler (__pid_t __pid, int __policy,
+ __const struct sched_param *__param) __THROW;
+
+/* Retrieve scheduling algorithm for a particular purpose. */
+extern int sched_getscheduler (__pid_t __pid) __THROW;
+
+/* Yield the processor. */
+extern int sched_yield (void) __THROW;
+
+/* Get maximum priority value for a scheduler. */
+extern int sched_get_priority_max (int __algorithm) __THROW;
+
+/* Get minimum priority value for a scheduler. */
+extern int sched_get_priority_min (int __algorithm) __THROW;
+
+/* Get the SCHED_RR interval for the named process. */
+extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __THROW;
+
+
+#ifdef __USE_GNU
+/* Access macros for `cpu_set'. */
+#define CPU_SETSIZE __CPU_SETSIZE
+#define CPU_SET(cpu, cpusetp) __CPU_SET (cpu, cpusetp)
+#define CPU_CLR(cpu, cpusetp) __CPU_CLR (cpu, cpusetp)
+#define CPU_ISSET(cpu, cpusetp) __CPU_ISSET (cpu, cpusetp)
+#define CPU_ZERO(cpusetp) __CPU_ZERO (cpusetp)
+
+
+/* Set the CPU affinity for a task */
+extern int sched_setaffinity (__pid_t __pid, size_t __cpusetsize,
+ __const cpu_set_t *__cpuset) __THROW;
+
+/* Get the CPU affinity for a task */
+extern int sched_getaffinity (__pid_t __pid, size_t __cpusetsize,
+ cpu_set_t *__cpuset) __THROW;
+#endif
+
+__END_DECLS
+
+#endif /* sched.h */
diff --git a/libc/posix/sched_getaffinity.c b/libc/posix/sched_getaffinity.c
new file mode 100644
index 000000000..b2e452f87
--- /dev/null
+++ b/libc/posix/sched_getaffinity.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+
+
+/* Retrieve the CPU affinity mask for a particular process. */
+int
+sched_getaffinity (pid, cpusetsize, cpuset)
+ pid_t pid;
+ size_t cpusetsize;
+ cpu_set_t *cpuset;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_getaffinity)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_getp.c b/libc/posix/sched_getp.c
new file mode 100644
index 000000000..1ca77893f
--- /dev/null
+++ b/libc/posix/sched_getp.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sched.h>
+
+
+/* Retrieve scheduling parameters for a particular process. */
+int
+__sched_getparam (pid_t pid, struct sched_param *param)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_getparam)
+
+weak_alias (__sched_getparam, sched_getparam)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_gets.c b/libc/posix/sched_gets.c
new file mode 100644
index 000000000..479b913f3
--- /dev/null
+++ b/libc/posix/sched_gets.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+
+
+/* Retrieve scheduling algorithm for a particular purpose. */
+int
+__sched_getscheduler (pid_t pid)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_getscheduler)
+
+weak_alias (__sched_getscheduler, sched_getscheduler)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_primax.c b/libc/posix/sched_primax.c
new file mode 100644
index 000000000..4b3c1cbe6
--- /dev/null
+++ b/libc/posix/sched_primax.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+
+
+/* Get maximum priority value for a scheduler. */
+int
+__sched_get_priority_max (int algorithm)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_get_priority_max)
+
+weak_alias (__sched_get_priority_max, sched_get_priority_max)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_primin.c b/libc/posix/sched_primin.c
new file mode 100644
index 000000000..813b8f63c
--- /dev/null
+++ b/libc/posix/sched_primin.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+
+
+/* Get minimum priority value for a scheduler. */
+int
+__sched_get_priority_min (int algorithm)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_get_priority_min)
+
+weak_alias (__sched_get_priority_min, sched_get_priority_min)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_rr_gi.c b/libc/posix/sched_rr_gi.c
new file mode 100644
index 000000000..f8fec6361
--- /dev/null
+++ b/libc/posix/sched_rr_gi.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+
+
+/* Get the SCHED_RR interval for the named process. */
+int
+__sched_rr_get_interval (pid_t pid, struct timespec *t)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_rr_get_interval)
+
+weak_alias (__sched_rr_get_interval, sched_rr_get_interval)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_setaffinity.c b/libc/posix/sched_setaffinity.c
new file mode 100644
index 000000000..652163db8
--- /dev/null
+++ b/libc/posix/sched_setaffinity.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sched.h>
+
+
+/* Retrieve the CPU affinity mask for a particular process. */
+int
+sched_setaffinity (pid, cpusetsize, cpuset)
+ pid_t pid;
+ size_t cpusetsize;
+ const cpu_set_t *cpuset;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_setaffinity)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_setp.c b/libc/posix/sched_setp.c
new file mode 100644
index 000000000..cc451fc13
--- /dev/null
+++ b/libc/posix/sched_setp.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sched.h>
+
+
+/* Set scheduling parameters for a process. */
+int
+__sched_setparam (pid_t pid, const struct sched_param *param)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_setparam)
+
+weak_alias (__sched_setparam, sched_setparam)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_sets.c b/libc/posix/sched_sets.c
new file mode 100644
index 000000000..631cac228
--- /dev/null
+++ b/libc/posix/sched_sets.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+
+
+/* Set scheduling algorithm and/or parameters for a process. */
+int
+__sched_setscheduler (pid_t pid, int policy, const struct sched_param *param)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__sched_setscheduler)
+stub_warning (sched_setscheduler)
+
+weak_alias (__sched_setscheduler, sched_setscheduler)
+#include <stub-tag.h>
diff --git a/libc/posix/sched_yield.c b/libc/posix/sched_yield.c
new file mode 100644
index 000000000..e7a41ea80
--- /dev/null
+++ b/libc/posix/sched_yield.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1996, 1997, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+
+
+/* Yield the processor. */
+int
+__sched_yield (void)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (sched_yield)
+libc_hidden_def (__sched_yield)
+
+weak_alias (__sched_yield, sched_yield)
+#include <stub-tag.h>
diff --git a/libc/posix/setgid.c b/libc/posix/setgid.c
new file mode 100644
index 000000000..05c2cc662
--- /dev/null
+++ b/libc/posix/setgid.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Set the group ID of the calling process to GID.
+ If the calling process is the super-user, the real
+ and effective group IDs, and the saved set-group-ID to GID;
+ if not, the effective group ID is set to GID. */
+int
+__setgid (gid)
+ gid_t gid;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (setgid)
+
+weak_alias (__setgid, setgid)
+#include <stub-tag.h>
diff --git a/libc/posix/setlogin.c b/libc/posix/setlogin.c
new file mode 100644
index 000000000..c16e29dd9
--- /dev/null
+++ b/libc/posix/setlogin.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Set the login name returned by `getlogin'. */
+int
+setlogin (name)
+ const char *name;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (setlogin)
+#include <stub-tag.h>
diff --git a/libc/posix/setpgid.c b/libc/posix/setpgid.c
new file mode 100644
index 000000000..cb2abf115
--- /dev/null
+++ b/libc/posix/setpgid.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Set the process group ID of the process matching PID to PGID.
+ If PID is zero, the current process's process group ID is set.
+ If PGID is zero, the process ID of the process is used. */
+int
+__setpgid (pid, pgid)
+ int pid;
+ int pgid;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__setpgid)
+stub_warning (setpgid)
+
+weak_alias (__setpgid, setpgid)
+#include <stub-tag.h>
diff --git a/libc/posix/setpgrp.c b/libc/posix/setpgrp.c
new file mode 100644
index 000000000..8ceb15934
--- /dev/null
+++ b/libc/posix/setpgrp.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+
+int
+setpgrp ()
+{
+ return __setpgid (0, 0);
+}
diff --git a/libc/posix/setresgid.c b/libc/posix/setresgid.c
new file mode 100644
index 000000000..736c22e4c
--- /dev/null
+++ b/libc/posix/setresgid.c
@@ -0,0 +1,35 @@
+/* setresgid -- set real group ID, effective group ID, and saved-set group ID
+ Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Set the real group ID, effective group ID, and saved-set group ID,
+ of the calling process to RGID, EGID, and SGID, respectively. */
+int
+__setresgid (gid_t rgid, gid_t egid, gid_t sgid)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__setresgid)
+stub_warning (setresgid)
+
+weak_alias (__setresgid, setresgid)
+#include <stub-tag.h>
diff --git a/libc/posix/setresuid.c b/libc/posix/setresuid.c
new file mode 100644
index 000000000..89263330e
--- /dev/null
+++ b/libc/posix/setresuid.c
@@ -0,0 +1,35 @@
+/* setresuid -- set real user ID, effective user ID, and saved-set user ID
+ Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Set the real user ID, effective user ID, and saved-set user ID,
+ of the calling process to RUID, EUID, and SUID, respectively. */
+int
+__setresuid (uid_t ruid, uid_t euid, uid_t suid)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__setresuid)
+stub_warning (setresuid)
+
+weak_alias (__setresuid, setresuid)
+#include <stub-tag.h>
diff --git a/libc/posix/setsid.c b/libc/posix/setsid.c
new file mode 100644
index 000000000..6a6712b9b
--- /dev/null
+++ b/libc/posix/setsid.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Create a new session with the calling process as its leader.
+ The process group IDs of the session and the calling process
+ are set to the process ID of the calling process, which is returned. */
+int
+__setsid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (setsid)
+
+weak_alias (__setsid, setsid)
+#include <stub-tag.h>
diff --git a/libc/posix/setuid.c b/libc/posix/setuid.c
new file mode 100644
index 000000000..96c3e01cb
--- /dev/null
+++ b/libc/posix/setuid.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Set the user ID of the calling process to UID.
+ If the calling process is the super-user, the real
+ and effective user IDs, and the saved set-user-ID to UID;
+ if not, the effective user ID is set to UID. */
+int
+__setuid (uid)
+ uid_t uid;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (setuid)
+
+weak_alias (__setuid, setuid)
+#include <stub-tag.h>
diff --git a/libc/posix/sleep.c b/libc/posix/sleep.c
new file mode 100644
index 000000000..f9d2a6593
--- /dev/null
+++ b/libc/posix/sleep.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* Make the process sleep for SECONDS seconds, or until a signal arrives
+ and is not ignored. The function returns the number of seconds less
+ than SECONDS which it actually slept (zero if it slept the full time).
+ If a signal handler does a `longjmp' or modifies the handling of the
+ SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
+ signal afterwards is undefined. There is no return value to indicate
+ error, but if `sleep' returns SECONDS, it probably didn't work. */
+unsigned int
+__sleep (seconds)
+ unsigned int seconds;
+{
+ __set_errno (ENOSYS);
+ return seconds;
+}
+weak_alias (__sleep, sleep)
+
+stub_warning (sleep)
+#include <stub-tag.h>
diff --git a/libc/posix/spawn.c b/libc/posix/spawn.c
new file mode 100644
index 000000000..b93b320d0
--- /dev/null
+++ b/libc/posix/spawn.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include "spawn_int.h"
+
+/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
+ Before running the process perform the actions described in FILE-ACTIONS. */
+int
+posix_spawn (pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[])
+{
+ return __spawni (pid, path, file_actions, attrp, argv, envp, 0);
+}
diff --git a/libc/posix/spawn.h b/libc/posix/spawn.h
new file mode 100644
index 000000000..ff77fcc8f
--- /dev/null
+++ b/libc/posix/spawn.h
@@ -0,0 +1,190 @@
+/* Definitions for POSIX spawn interface.
+ Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SPAWN_H
+#define _SPAWN_H 1
+
+#include <features.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/types.h>
+
+
+/* Data structure to contain attributes for thread creation. */
+typedef struct
+{
+ short int __flags;
+ pid_t __pgrp;
+ sigset_t __sd;
+ sigset_t __ss;
+ struct sched_param __sp;
+ int __policy;
+ int __pad[16];
+} posix_spawnattr_t;
+
+
+/* Data structure to contain information about the actions to be
+ performed in the new process with respect to file descriptors. */
+typedef struct
+{
+ int __allocated;
+ int __used;
+ struct __spawn_action *__actions;
+ int __pad[16];
+} posix_spawn_file_actions_t;
+
+
+/* Flags to be set in the `posix_spawnattr_t'. */
+#define POSIX_SPAWN_RESETIDS 0x01
+#define POSIX_SPAWN_SETPGROUP 0x02
+#define POSIX_SPAWN_SETSIGDEF 0x04
+#define POSIX_SPAWN_SETSIGMASK 0x08
+#define POSIX_SPAWN_SETSCHEDPARAM 0x10
+#define POSIX_SPAWN_SETSCHEDULER 0x20
+#ifdef __USE_GNU
+# define POSIX_SPAWN_USEVFORK 0x40
+#endif
+
+
+__BEGIN_DECLS
+
+/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
+ Before running the process perform the actions described in FILE-ACTIONS.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern int posix_spawn (pid_t *__restrict __pid,
+ __const char *__restrict __path,
+ __const posix_spawn_file_actions_t *__restrict
+ __file_actions,
+ __const posix_spawnattr_t *__restrict __attrp,
+ char *__const argv[__restrict_arr],
+ char *__const envp[__restrict_arr]);
+
+/* Similar to `posix_spawn' but search for FILE in the PATH.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern int posix_spawnp (pid_t *__pid, __const char *__file,
+ __const posix_spawn_file_actions_t *__file_actions,
+ __const posix_spawnattr_t *__attrp,
+ char *__const argv[], char *__const envp[]);
+
+
+/* Initialize data structure with attributes for `spawn' to default values. */
+extern int posix_spawnattr_init (posix_spawnattr_t *__attr) __THROW;
+
+/* Free resources associated with ATTR. */
+extern int posix_spawnattr_destroy (posix_spawnattr_t *__attr) __THROW;
+
+/* Store signal mask for signals with default handling from ATTR in
+ SIGDEFAULT. */
+extern int posix_spawnattr_getsigdefault (__const posix_spawnattr_t *
+ __restrict __attr,
+ sigset_t *__restrict __sigdefault)
+ __THROW;
+
+/* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */
+extern int posix_spawnattr_setsigdefault (posix_spawnattr_t *__restrict __attr,
+ __const sigset_t *__restrict
+ __sigdefault)
+ __THROW;
+
+/* Store signal mask for the new process from ATTR in SIGMASK. */
+extern int posix_spawnattr_getsigmask (__const posix_spawnattr_t *__restrict
+ __attr,
+ sigset_t *__restrict __sigmask) __THROW;
+
+/* Set signal mask for the new process in ATTR to SIGMASK. */
+extern int posix_spawnattr_setsigmask (posix_spawnattr_t *__restrict __attr,
+ __const sigset_t *__restrict __sigmask)
+ __THROW;
+
+/* Get flag word from the attribute structure. */
+extern int posix_spawnattr_getflags (__const posix_spawnattr_t *__restrict
+ __attr,
+ short int *__restrict __flags) __THROW;
+
+/* Store flags in the attribute structure. */
+extern int posix_spawnattr_setflags (posix_spawnattr_t *_attr,
+ short int __flags) __THROW;
+
+/* Get process group ID from the attribute structure. */
+extern int posix_spawnattr_getpgroup (__const posix_spawnattr_t *__restrict
+ __attr, pid_t *__restrict __pgroup)
+ __THROW;
+
+/* Store process group ID in the attribute structure. */
+extern int posix_spawnattr_setpgroup (posix_spawnattr_t *__attr,
+ pid_t __pgroup) __THROW;
+
+/* Get scheduling policy from the attribute structure. */
+extern int posix_spawnattr_getschedpolicy (__const posix_spawnattr_t *
+ __restrict __attr,
+ int *__restrict __schedpolicy)
+ __THROW;
+
+/* Store scheduling policy in the attribute structure. */
+extern int posix_spawnattr_setschedpolicy (posix_spawnattr_t *__attr,
+ int __schedpolicy) __THROW;
+
+/* Get scheduling parameters from the attribute structure. */
+extern int posix_spawnattr_getschedparam (__const posix_spawnattr_t *
+ __restrict __attr,
+ struct sched_param *__restrict
+ __schedparam) __THROW;
+
+/* Store scheduling parameters in the attribute structure. */
+extern int posix_spawnattr_setschedparam (posix_spawnattr_t *__restrict __attr,
+ const struct sched_param *
+ __restrict __schedparam) __THROW;
+
+
+/* Initialize data structure for file attribute for `spawn' call. */
+extern int posix_spawn_file_actions_init (posix_spawn_file_actions_t *
+ __file_actions) __THROW;
+
+/* Free resources associated with FILE-ACTIONS. */
+extern int posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *
+ __file_actions) __THROW;
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `open' for the given file during the `spawn' call. */
+extern int posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *
+ __restrict __file_actions,
+ int __fd,
+ __const char *__restrict __path,
+ int __oflag, mode_t __mode)
+ __THROW;
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `close' for the given file descriptor during the `spawn' call. */
+extern int posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *
+ __file_actions, int __fd)
+ __THROW;
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `dup2' for the given file descriptors during the `spawn' call. */
+extern int posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *
+ __file_actions,
+ int __fd, int __newfd) __THROW;
+
+__END_DECLS
+
+#endif /* spawn.h */
diff --git a/libc/posix/spawn_faction_addclose.c b/libc/posix/spawn_faction_addclose.c
new file mode 100644
index 000000000..cb2b9b4de
--- /dev/null
+++ b/libc/posix/spawn_faction_addclose.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <unistd.h>
+
+#include "spawn_int.h"
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `close' for the given file descriptor during the `spawn' call. */
+int
+posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions,
+ int fd)
+{
+ int maxfd = __sysconf (_SC_OPEN_MAX);
+ struct __spawn_action *rec;
+
+ /* Test for the validity of the file descriptor. */
+ if (fd < 0 || fd >= maxfd)
+ return EBADF;
+
+ /* Allocate more memory if needed. */
+ if (file_actions->__used == file_actions->__allocated
+ && __posix_spawn_file_actions_realloc (file_actions) != 0)
+ /* This can only mean we ran out of memory. */
+ return ENOMEM;
+
+ /* Add the new value. */
+ rec = &file_actions->__actions[file_actions->__used];
+ rec->tag = spawn_do_close;
+ rec->action.open_action.fd = fd;
+
+ /* Account for the new entry. */
+ ++file_actions->__used;
+
+ return 0;
+}
diff --git a/libc/posix/spawn_faction_adddup2.c b/libc/posix/spawn_faction_adddup2.c
new file mode 100644
index 000000000..bc8183b05
--- /dev/null
+++ b/libc/posix/spawn_faction_adddup2.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <unistd.h>
+
+#include "spawn_int.h"
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `dup2' for the given file descriptors during the `spawn' call. */
+int
+posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions,
+ int fd, int newfd)
+{
+ int maxfd = __sysconf (_SC_OPEN_MAX);
+ struct __spawn_action *rec;
+
+ /* Test for the validity of the file descriptor. */
+ if (fd < 0 || newfd < 0 || fd >= maxfd || newfd >= maxfd)
+ return EBADF;
+
+ /* Allocate more memory if needed. */
+ if (file_actions->__used == file_actions->__allocated
+ && __posix_spawn_file_actions_realloc (file_actions) != 0)
+ /* This can only mean we ran out of memory. */
+ return ENOMEM;
+
+ /* Add the new value. */
+ rec = &file_actions->__actions[file_actions->__used];
+ rec->tag = spawn_do_dup2;
+ rec->action.dup2_action.fd = fd;
+ rec->action.dup2_action.newfd = newfd;
+
+ /* Account for the new entry. */
+ ++file_actions->__used;
+
+ return 0;
+}
diff --git a/libc/posix/spawn_faction_addopen.c b/libc/posix/spawn_faction_addopen.c
new file mode 100644
index 000000000..f0fa4c0b5
--- /dev/null
+++ b/libc/posix/spawn_faction_addopen.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <unistd.h>
+
+#include "spawn_int.h"
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+ `open' for the given file during the `spawn' call. */
+int
+posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
+ int fd, const char *path, int oflag,
+ mode_t mode)
+{
+ int maxfd = __sysconf (_SC_OPEN_MAX);
+ struct __spawn_action *rec;
+
+ /* Test for the validity of the file descriptor. */
+ if (fd < 0 || fd >= maxfd)
+ return EBADF;
+
+ /* Allocate more memory if needed. */
+ if (file_actions->__used == file_actions->__allocated
+ && __posix_spawn_file_actions_realloc (file_actions) != 0)
+ /* This can only mean we ran out of memory. */
+ return ENOMEM;
+
+ /* Add the new value. */
+ rec = &file_actions->__actions[file_actions->__used];
+ rec->tag = spawn_do_open;
+ rec->action.open_action.fd = fd;
+ rec->action.open_action.path = path;
+ rec->action.open_action.oflag = oflag;
+ rec->action.open_action.mode = mode;
+
+ /* Account for the new entry. */
+ ++file_actions->__used;
+
+ return 0;
+}
diff --git a/libc/posix/spawn_faction_destroy.c b/libc/posix/spawn_faction_destroy.c
new file mode 100644
index 000000000..aed3bae7b
--- /dev/null
+++ b/libc/posix/spawn_faction_destroy.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <stdlib.h>
+
+/* Initialize data structure for file attribute for `spawn' call. */
+int
+posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
+{
+ /* Free the memory allocated. */
+ free (file_actions->__actions);
+ return 0;
+}
diff --git a/libc/posix/spawn_faction_init.c b/libc/posix/spawn_faction_init.c
new file mode 100644
index 000000000..66356bb79
--- /dev/null
+++ b/libc/posix/spawn_faction_init.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "spawn_int.h"
+
+
+/* Function used to increase the size of the allocated array. This
+ function is called from the `add'-functions. */
+int
+__posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *file_actions)
+{
+ int newalloc = file_actions->__allocated + 8;
+ void *newmem = realloc (file_actions->__actions,
+ newalloc * sizeof (struct __spawn_action));
+
+ if (newmem == NULL)
+ /* Not enough memory. */
+ return ENOMEM;
+
+ file_actions->__actions = (struct __spawn_action *) newmem;
+ file_actions->__allocated = newalloc;
+
+ return 0;
+}
+
+
+/* Initialize data structure for file attribute for `spawn' call. */
+int
+posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions)
+{
+ /* Simply clear all the elements. */
+ memset (file_actions, '\0', sizeof (*file_actions));
+ return 0;
+}
diff --git a/libc/posix/spawn_int.h b/libc/posix/spawn_int.h
new file mode 100644
index 000000000..a3e934754
--- /dev/null
+++ b/libc/posix/spawn_int.h
@@ -0,0 +1,38 @@
+/* Data structure to contain the action information. */
+struct __spawn_action
+{
+ enum
+ {
+ spawn_do_close,
+ spawn_do_dup2,
+ spawn_do_open
+ } tag;
+
+ union
+ {
+ struct
+ {
+ int fd;
+ } close_action;
+ struct
+ {
+ int fd;
+ int newfd;
+ } dup2_action;
+ struct
+ {
+ int fd;
+ const char *path;
+ int oflag;
+ mode_t mode;
+ } open_action;
+ } action;
+};
+
+extern int __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *
+ file_actions);
+
+extern int __spawni (pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[], int use_path);
diff --git a/libc/posix/spawnattr_destroy.c b/libc/posix/spawnattr_destroy.c
new file mode 100644
index 000000000..534c014ba
--- /dev/null
+++ b/libc/posix/spawnattr_destroy.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+
+/* Initialize data structure for file attribute for `spawn' call. */
+int
+posix_spawnattr_destroy (posix_spawnattr_t *attr)
+{
+ /* Nothing to do in the moment. */
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getdefault.c b/libc/posix/spawnattr_getdefault.c
new file mode 100644
index 000000000..a2116f111
--- /dev/null
+++ b/libc/posix/spawnattr_getdefault.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Store signal mask for signals with default handling from ATTR in
+ SIGDEFAULT. */
+int
+posix_spawnattr_getsigdefault (const posix_spawnattr_t *attr,
+ sigset_t *sigdefault)
+{
+ /* Copy the sigset_t data to the user buffer. */
+ memcpy (sigdefault, &attr->__sd, sizeof (sigset_t));
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getflags.c b/libc/posix/spawnattr_getflags.c
new file mode 100644
index 000000000..6365294a9
--- /dev/null
+++ b/libc/posix/spawnattr_getflags.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Get flag word from the attribute structure. */
+int
+posix_spawnattr_getflags (const posix_spawnattr_t *attr, short int *flags)
+{
+ /* Copy the flag word. */
+ *flags = attr->__flags;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getpgroup.c b/libc/posix/spawnattr_getpgroup.c
new file mode 100644
index 000000000..7963f6831
--- /dev/null
+++ b/libc/posix/spawnattr_getpgroup.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Get process group ID from the attribute structure. */
+int
+posix_spawnattr_getpgroup (const posix_spawnattr_t *attr, pid_t *pgroup)
+{
+ /* Copy the process group ID. */
+ *pgroup = attr->__pgrp;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getschedparam.c b/libc/posix/spawnattr_getschedparam.c
new file mode 100644
index 000000000..f33b622b2
--- /dev/null
+++ b/libc/posix/spawnattr_getschedparam.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Get scheduling parameters from the attribute structure. */
+int
+posix_spawnattr_getschedparam (const posix_spawnattr_t *attr,
+ struct sched_param *schedparam)
+{
+ /* Copy the scheduling parameters. */
+ memcpy (schedparam, &attr->__sp, sizeof (*attr));
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getschedpolicy.c b/libc/posix/spawnattr_getschedpolicy.c
new file mode 100644
index 000000000..f0ce1b643
--- /dev/null
+++ b/libc/posix/spawnattr_getschedpolicy.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Get scheduling policy from the attribute structure. */
+int
+posix_spawnattr_getschedpolicy (const posix_spawnattr_t *attr,
+ int *schedpolicy)
+{
+ /* Copy the scheduling policy. */
+ *schedpolicy = attr->__policy;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_getsigmask.c b/libc/posix/spawnattr_getsigmask.c
new file mode 100644
index 000000000..95a035118
--- /dev/null
+++ b/libc/posix/spawnattr_getsigmask.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Store signal mask for the new process from ATTR in SIGMASK. */
+int
+posix_spawnattr_getsigmask (const posix_spawnattr_t *attr,
+ sigset_t *sigmask)
+{
+ /* Copy the sigset_t data to the user buffer. */
+ memcpy (sigmask, &attr->__ss, sizeof (sigset_t));
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_init.c b/libc/posix/spawnattr_init.c
new file mode 100644
index 000000000..0d967853d
--- /dev/null
+++ b/libc/posix/spawnattr_init.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Initialize data structure for file attribute for `spawn' call. */
+int
+posix_spawnattr_init (posix_spawnattr_t *attr)
+{
+ /* All elements have to be initialized to the default values which
+ is generally zero. */
+ memset (attr, '\0', sizeof (*attr));
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setdefault.c b/libc/posix/spawnattr_setdefault.c
new file mode 100644
index 000000000..34af0bd91
--- /dev/null
+++ b/libc/posix/spawnattr_setdefault.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */
+int
+posix_spawnattr_setsigdefault (posix_spawnattr_t *attr,
+ const sigset_t *sigdefault)
+{
+ /* Copy the sigset_t data to the user buffer. */
+ memcpy (&attr->__sd, sigdefault, sizeof (sigset_t));
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setflags.c b/libc/posix/spawnattr_setflags.c
new file mode 100644
index 000000000..0c3f5d20b
--- /dev/null
+++ b/libc/posix/spawnattr_setflags.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <string.h>
+
+#define ALL_FLAGS (POSIX_SPAWN_RESETIDS \
+ | POSIX_SPAWN_SETPGROUP \
+ | POSIX_SPAWN_SETSIGDEF \
+ | POSIX_SPAWN_SETSIGMASK \
+ | POSIX_SPAWN_SETSCHEDPARAM \
+ | POSIX_SPAWN_SETSCHEDULER \
+ | POSIX_SPAWN_USEVFORK)
+
+/* Store flags in the attribute structure. */
+int
+posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags)
+{
+ /* Check no invalid bits are set. */
+ if (flags & ~ALL_FLAGS)
+ return EINVAL;
+
+ /* Store the flag word. */
+ attr->__flags = flags;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setpgroup.c b/libc/posix/spawnattr_setpgroup.c
new file mode 100644
index 000000000..4bbdcf5b3
--- /dev/null
+++ b/libc/posix/spawnattr_setpgroup.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Store process group ID in the attribute structure. */
+int
+posix_spawnattr_setpgroup (posix_spawnattr_t *attr, pid_t pgroup)
+{
+ /* Store the process group ID. */
+ attr->__pgrp = pgroup;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setschedparam.c b/libc/posix/spawnattr_setschedparam.c
new file mode 100644
index 000000000..b74208049
--- /dev/null
+++ b/libc/posix/spawnattr_setschedparam.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Store scheduling parameters in the attribute structure. */
+int
+posix_spawnattr_setschedparam (posix_spawnattr_t *attr,
+ const struct sched_param *schedparam)
+{
+ /* Store the scheduling parameters. */
+ attr->__sp = *schedparam;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setschedpolicy.c b/libc/posix/spawnattr_setschedpolicy.c
new file mode 100644
index 000000000..8cbd259d1
--- /dev/null
+++ b/libc/posix/spawnattr_setschedpolicy.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+
+/* Store scheduling policy in the attribute structure. */
+int
+posix_spawnattr_setschedpolicy (posix_spawnattr_t *attr, int schedpolicy)
+{
+ if (schedpolicy != SCHED_OTHER && schedpolicy != SCHED_FIFO
+ && schedpolicy != SCHED_RR)
+ return EINVAL;
+
+ /* Store the policy. */
+ attr->__policy = schedpolicy;
+
+ return 0;
+}
diff --git a/libc/posix/spawnattr_setsigmask.c b/libc/posix/spawnattr_setsigmask.c
new file mode 100644
index 000000000..cbb6690db
--- /dev/null
+++ b/libc/posix/spawnattr_setsigmask.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include <string.h>
+
+/* Set signal mask for the new process in ATTR to SIGMASK. */
+int
+posix_spawnattr_setsigmask (posix_spawnattr_t *attr,
+ const sigset_t *sigmask)
+{
+ /* Copy the sigset_t data to the user buffer. */
+ memcpy (&attr->__ss, sigmask, sizeof (sigset_t));
+
+ return 0;
+}
diff --git a/libc/posix/spawni.c b/libc/posix/spawni.c
new file mode 100644
index 000000000..c7d5f59ff
--- /dev/null
+++ b/libc/posix/spawni.c
@@ -0,0 +1,46 @@
+/* Guts of POSIX spawn interface. Stub version.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <spawn.h>
+#include "spawn_int.h"
+
+
+/* The Unix standard contains a long explanation of the way to signal
+ an error after the fork() was successful. Since no new wait status
+ was wanted there is no way to signal an error using one of the
+ available methods. The committee chose to signal an error by a
+ normal program exit with the exit code 127. */
+#define SPAWN_ERROR 127
+
+
+/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
+ Before running the process perform the actions described in FILE-ACTIONS. */
+int
+__spawni (pid_t *pid, const char *file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[], int use_path)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (__spawni)
+#include <stub-tag.h>
diff --git a/libc/posix/spawnp.c b/libc/posix/spawnp.c
new file mode 100644
index 000000000..2b15391be
--- /dev/null
+++ b/libc/posix/spawnp.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include "spawn_int.h"
+
+/* Spawn a new process executing FILE with the attributes describes in *ATTRP.
+ Before running the process perform the actions described in FILE-ACTIONS. */
+int
+posix_spawnp (pid_t *pid, const char *file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[])
+{
+ return __spawni (pid, file, file_actions, attrp, argv, envp, 1);
+}
diff --git a/libc/posix/sys/times.h b/libc/posix/sys/times.h
new file mode 100644
index 000000000..6022f2f84
--- /dev/null
+++ b/libc/posix/sys/times.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1991, 1992, 1996, 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 4.5.2 Process Times <sys/times.h>
+ */
+
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H 1
+
+#include <features.h>
+
+#define __need_clock_t
+#include <time.h>
+
+
+__BEGIN_DECLS
+
+/* Structure describing CPU time used by a process and its children. */
+struct tms
+ {
+ clock_t tms_utime; /* User CPU time. */
+ clock_t tms_stime; /* System CPU time. */
+
+ clock_t tms_cutime; /* User CPU time of dead children. */
+ clock_t tms_cstime; /* System CPU time of dead children. */
+ };
+
+
+/* Store the CPU time used by this process and all its
+ dead children (and their dead children) in BUFFER.
+ Return the elapsed real time, or (clock_t) -1 for errors.
+ All times are in CLK_TCKths of a second. */
+extern clock_t times (struct tms *__buffer) __THROW;
+
+__END_DECLS
+
+#endif /* sys/times.h */
diff --git a/libc/posix/sys/types.h b/libc/posix/sys/types.h
new file mode 100644
index 000000000..04563a4ab
--- /dev/null
+++ b/libc/posix/sys/types.h
@@ -0,0 +1,275 @@
+/* Copyright (C) 1991,1992,1994,1995,1996,1997,1998,1999,2000,2001,2002,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 2.6 Primitive System Data Types <sys/types.h>
+ */
+
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#include <bits/types.h>
+
+#ifdef __USE_BSD
+# ifndef __u_char_defined
+typedef __u_char u_char;
+typedef __u_short u_short;
+typedef __u_int u_int;
+typedef __u_long u_long;
+typedef __quad_t quad_t;
+typedef __u_quad_t u_quad_t;
+typedef __fsid_t fsid_t;
+# define __u_char_defined
+# endif
+#endif
+
+typedef __loff_t loff_t;
+
+#ifndef __ino_t_defined
+# ifndef __USE_FILE_OFFSET64
+typedef __ino_t ino_t;
+# else
+typedef __ino64_t ino_t;
+# endif
+# define __ino_t_defined
+#endif
+#if defined __USE_LARGEFILE64 && !defined __ino64_t_defined
+typedef __ino64_t ino64_t;
+# define __ino64_t_defined
+#endif
+
+#ifndef __dev_t_defined
+typedef __dev_t dev_t;
+# define __dev_t_defined
+#endif
+
+#ifndef __gid_t_defined
+typedef __gid_t gid_t;
+# define __gid_t_defined
+#endif
+
+#ifndef __mode_t_defined
+typedef __mode_t mode_t;
+# define __mode_t_defined
+#endif
+
+#ifndef __nlink_t_defined
+typedef __nlink_t nlink_t;
+# define __nlink_t_defined
+#endif
+
+#ifndef __uid_t_defined
+typedef __uid_t uid_t;
+# define __uid_t_defined
+#endif
+
+#ifndef __off_t_defined
+# ifndef __USE_FILE_OFFSET64
+typedef __off_t off_t;
+# else
+typedef __off64_t off_t;
+# endif
+# define __off_t_defined
+#endif
+#if defined __USE_LARGEFILE64 && !defined __off64_t_defined
+typedef __off64_t off64_t;
+# define __off64_t_defined
+#endif
+
+#ifndef __pid_t_defined
+typedef __pid_t pid_t;
+# define __pid_t_defined
+#endif
+
+#if (defined __USE_SVID || defined __USE_XOPEN) && !defined __id_t_defined
+typedef __id_t id_t;
+# define __id_t_defined
+#endif
+
+#ifndef __ssize_t_defined
+typedef __ssize_t ssize_t;
+# define __ssize_t_defined
+#endif
+
+#ifdef __USE_BSD
+# ifndef __daddr_t_defined
+typedef __daddr_t daddr_t;
+typedef __caddr_t caddr_t;
+# define __daddr_t_defined
+# endif
+#endif
+
+#if (defined __USE_SVID || defined __USE_XOPEN) && !defined __key_t_defined
+typedef __key_t key_t;
+# define __key_t_defined
+#endif
+
+#ifdef __USE_XOPEN
+# define __need_clock_t
+#endif
+#define __need_time_t
+#define __need_timer_t
+#define __need_clockid_t
+#include <time.h>
+
+#ifdef __USE_XOPEN
+# ifndef __useconds_t_defined
+typedef __useconds_t useconds_t;
+# define __useconds_t_defined
+# endif
+# ifndef __suseconds_t_defined
+typedef __suseconds_t suseconds_t;
+# define __suseconds_t_defined
+# endif
+#endif
+
+#define __need_size_t
+#include <stddef.h>
+
+#ifdef __USE_MISC
+/* Old compatibility names for C types. */
+typedef unsigned long int ulong;
+typedef unsigned short int ushort;
+typedef unsigned int uint;
+#endif
+
+/* These size-specific names are used by some of the inet code. */
+
+#if !__GNUC_PREREQ (2, 7)
+
+/* These types are defined by the ISO C99 header <inttypes.h>. */
+# ifndef __int8_t_defined
+# define __int8_t_defined
+typedef char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+# if __WORDSIZE == 64
+typedef long int int64_t;
+# elif __GLIBC_HAVE_LONG_LONG
+__extension__ typedef long long int int64_t;
+# endif
+# endif
+
+/* But these were defined by ISO C without the first `_'. */
+typedef unsigned char u_int8_t;
+typedef unsigned short int u_int16_t;
+typedef unsigned int u_int32_t;
+# if __WORDSIZE == 64
+typedef unsigned long int u_int64_t;
+# elif __GLIBC_HAVE_LONG_LONG
+__extension__ typedef unsigned long long int u_int64_t;
+# endif
+
+typedef int register_t;
+
+#else
+
+/* For GCC 2.7 and later, we can use specific type-size attributes. */
+# define __intN_t(N, MODE) \
+ typedef int int##N##_t __attribute__ ((__mode__ (MODE)))
+# define __u_intN_t(N, MODE) \
+ typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
+
+# ifndef __int8_t_defined
+# define __int8_t_defined
+__intN_t (8, __QI__);
+__intN_t (16, __HI__);
+__intN_t (32, __SI__);
+__intN_t (64, __DI__);
+# endif
+
+__u_intN_t (8, __QI__);
+__u_intN_t (16, __HI__);
+__u_intN_t (32, __SI__);
+__u_intN_t (64, __DI__);
+
+typedef int register_t __attribute__ ((__mode__ (__word__)));
+
+
+/* Some code from BIND tests this macro to see if the types above are
+ defined. */
+#endif
+#define __BIT_TYPES_DEFINED__ 1
+
+
+#ifdef __USE_BSD
+/* In BSD <sys/types.h> is expected to define BYTE_ORDER. */
+# include <endian.h>
+
+/* It also defines `fd_set' and the FD_* macros for `select'. */
+# include <sys/select.h>
+
+/* BSD defines these symbols, so we follow. */
+# include <sys/sysmacros.h>
+#endif /* Use BSD. */
+
+
+#if defined __USE_UNIX98 && !defined __blksize_t_defined
+typedef __blksize_t blksize_t;
+# define __blksize_t_defined
+#endif
+
+/* Types from the Large File Support interface. */
+#ifndef __USE_FILE_OFFSET64
+# ifndef __blkcnt_t_defined
+typedef __blkcnt_t blkcnt_t; /* Type to count number of disk blocks. */
+# define __blkcnt_t_defined
+# endif
+# ifndef __fsblkcnt_t_defined
+typedef __fsblkcnt_t fsblkcnt_t; /* Type to count file system blocks. */
+# define __fsblkcnt_t_defined
+# endif
+# ifndef __fsfilcnt_t_defined
+typedef __fsfilcnt_t fsfilcnt_t; /* Type to count file system inodes. */
+# define __fsfilcnt_t_defined
+# endif
+#else
+# ifndef __blkcnt_t_defined
+typedef __blkcnt64_t blkcnt_t; /* Type to count number of disk blocks. */
+# define __blkcnt_t_defined
+# endif
+# ifndef __fsblkcnt_t_defined
+typedef __fsblkcnt64_t fsblkcnt_t; /* Type to count file system blocks. */
+# define __fsblkcnt_t_defined
+# endif
+# ifndef __fsfilcnt_t_defined
+typedef __fsfilcnt64_t fsfilcnt_t; /* Type to count file system inodes. */
+# define __fsfilcnt_t_defined
+# endif
+#endif
+
+#ifdef __USE_LARGEFILE64
+typedef __blkcnt64_t blkcnt64_t; /* Type to count number of disk blocks. */
+typedef __fsblkcnt64_t fsblkcnt64_t; /* Type to count file system blocks. */
+typedef __fsfilcnt64_t fsfilcnt64_t; /* Type to count file system inodes. */
+#endif
+
+
+/* Now add the thread types. */
+#if defined __USE_POSIX199506 || defined __USE_UNIX98
+# include <bits/pthreadtypes.h>
+#endif
+
+__END_DECLS
+
+#endif /* sys/types.h */
diff --git a/libc/posix/sys/unistd.h b/libc/posix/sys/unistd.h
new file mode 100644
index 000000000..1e823fbd5
--- /dev/null
+++ b/libc/posix/sys/unistd.h
@@ -0,0 +1 @@
+#include <unistd.h>
diff --git a/libc/posix/sys/utsname.h b/libc/posix/sys/utsname.h
new file mode 100644
index 000000000..a03aab9fc
--- /dev/null
+++ b/libc/posix/sys/utsname.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 1991,92,94,96,97,99,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 4.4 System Identification <sys/utsname.h>
+ */
+
+#ifndef _SYS_UTSNAME_H
+#define _SYS_UTSNAME_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#include <bits/utsname.h>
+
+#ifndef _UTSNAME_SYSNAME_LENGTH
+# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH
+#endif
+#ifndef _UTSNAME_NODENAME_LENGTH
+# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH
+#endif
+#ifndef _UTSNAME_RELEASE_LENGTH
+# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH
+#endif
+#ifndef _UTSNAME_VERSION_LENGTH
+# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH
+#endif
+#ifndef _UTSNAME_MACHINE_LENGTH
+# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH
+#endif
+
+/* Structure describing the system and machine. */
+struct utsname
+ {
+ /* Name of the implementation of the operating system. */
+ char sysname[_UTSNAME_SYSNAME_LENGTH];
+
+ /* Name of this node on the network. */
+ char nodename[_UTSNAME_NODENAME_LENGTH];
+
+ /* Current release level of this implementation. */
+ char release[_UTSNAME_RELEASE_LENGTH];
+ /* Current version level of this release. */
+ char version[_UTSNAME_VERSION_LENGTH];
+
+ /* Name of the hardware type the system is running on. */
+ char machine[_UTSNAME_MACHINE_LENGTH];
+
+#if _UTSNAME_DOMAIN_LENGTH - 0
+ /* Name of the domain of this node on the network. */
+# ifdef __USE_GNU
+ char domainname[_UTSNAME_DOMAIN_LENGTH];
+# else
+ char __domainname[_UTSNAME_DOMAIN_LENGTH];
+# endif
+#endif
+ };
+
+#ifdef __USE_SVID
+/* Note that SVID assumes all members have the same size. */
+# define SYS_NMLN _UTSNAME_LENGTH
+#endif
+
+
+/* Put information about the system in NAME. */
+extern int uname (struct utsname *__name) __THROW;
+
+
+__END_DECLS
+
+#endif /* sys/utsname.h */
diff --git a/libc/posix/sys/wait.h b/libc/posix/sys/wait.h
new file mode 100644
index 000000000..d7a58eab1
--- /dev/null
+++ b/libc/posix/sys/wait.h
@@ -0,0 +1,186 @@
+/* Copyright (C) 1991-1994,1996-2001,2003,2004,2005
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 3.2.1 Wait for Process Termination <sys/wait.h>
+ */
+
+#ifndef _SYS_WAIT_H
+#define _SYS_WAIT_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#include <signal.h>
+#include <sys/resource.h>
+
+/* These macros could also be defined in <stdlib.h>. */
+#if !defined _STDLIB_H || !defined __USE_XOPEN
+/* This will define the `W*' macros for the flag
+ bits to `waitpid', `wait3', and `wait4'. */
+# include <bits/waitflags.h>
+
+# ifdef __USE_BSD
+
+/* Lots of hair to allow traditional BSD use of `union wait'
+ as well as POSIX.1 use of `int' for the status word. */
+
+# if defined __GNUC__ && !defined __cplusplus
+# define __WAIT_INT(status) \
+ (__extension__ (((union { __typeof(status) __in; int __i; }) \
+ { .__in = (status) }).__i))
+# else
+# define __WAIT_INT(status) (*(__const int *) &(status))
+# endif
+
+/* This is the type of the argument to `wait'. The funky union
+ causes redeclarations with ether `int *' or `union wait *' to be
+ allowed without complaint. __WAIT_STATUS_DEFN is the type used in
+ the actual function definitions. */
+
+# if !defined __GNUC__ || __GNUC__ < 2 || defined __cplusplus
+# define __WAIT_STATUS void *
+# define __WAIT_STATUS_DEFN void *
+# else
+/* This works in GCC 2.6.1 and later. */
+typedef union
+ {
+ union wait *__uptr;
+ int *__iptr;
+ } __WAIT_STATUS __attribute__ ((__transparent_union__));
+# define __WAIT_STATUS_DEFN int *
+# endif
+
+# else /* Don't use BSD. */
+
+# define __WAIT_INT(status) (status)
+# define __WAIT_STATUS int *
+# define __WAIT_STATUS_DEFN int *
+
+# endif /* Use BSD. */
+
+/* This will define all the `__W*' macros. */
+# include <bits/waitstatus.h>
+
+# define WEXITSTATUS(status) __WEXITSTATUS(__WAIT_INT(status))
+# define WTERMSIG(status) __WTERMSIG(__WAIT_INT(status))
+# define WSTOPSIG(status) __WSTOPSIG(__WAIT_INT(status))
+# define WIFEXITED(status) __WIFEXITED(__WAIT_INT(status))
+# define WIFSIGNALED(status) __WIFSIGNALED(__WAIT_INT(status))
+# define WIFSTOPPED(status) __WIFSTOPPED(__WAIT_INT(status))
+# ifdef __WIFCONTINUED
+# define WIFCONTINUED(status) __WIFCONTINUED(__WAIT_INT(status))
+# endif
+#endif /* <stdlib.h> not included. */
+
+#ifdef __USE_BSD
+# define WCOREFLAG __WCOREFLAG
+# define WCOREDUMP(status) __WCOREDUMP(__WAIT_INT(status))
+# define W_EXITCODE(ret, sig) __W_EXITCODE(ret, sig)
+# define W_STOPCODE(sig) __W_STOPCODE(sig)
+#endif
+
+/* The following values are used by the `waitid' function. */
+#if defined __USE_SVID || defined __USE_XOPEN
+typedef enum
+{
+ P_ALL, /* Wait for any child. */
+ P_PID, /* Wait for specified process. */
+ P_PGID /* Wait for members of process group. */
+} idtype_t;
+#endif
+
+
+/* Wait for a child to die. When one does, put its status in *STAT_LOC
+ and return its process ID. For errors, return (pid_t) -1.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern __pid_t wait (__WAIT_STATUS __stat_loc);
+
+#ifdef __USE_BSD
+/* Special values for the PID argument to `waitpid' and `wait4'. */
+# define WAIT_ANY (-1) /* Any process. */
+# define WAIT_MYPGRP 0 /* Any process in my process group. */
+#endif
+
+/* Wait for a child matching PID to die.
+ If PID is greater than 0, match any process whose process ID is PID.
+ If PID is (pid_t) -1, match any process.
+ If PID is (pid_t) 0, match any process with the
+ same process group as the current process.
+ If PID is less than -1, match any process whose
+ process group is the absolute value of PID.
+ If the WNOHANG bit is set in OPTIONS, and that child
+ is not already dead, return (pid_t) 0. If successful,
+ return PID and store the dead child's status in STAT_LOC.
+ Return (pid_t) -1 for errors. If the WUNTRACED bit is
+ set in OPTIONS, return status for stopped children; otherwise don't.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);
+
+#if defined __USE_SVID || defined __USE_XOPEN
+# define __need_siginfo_t
+# include <bits/siginfo.h>
+/* Wait for a childing matching IDTYPE and ID to change the status and
+ place appropriate information in *INFOP.
+ If IDTYPE is P_PID, match any process whose process ID is ID.
+ If IDTYPE is P_PGID, match any process whose process group is ID.
+ If IDTYPE is P_ALL, match any process.
+ If the WNOHANG bit is set in OPTIONS, and that child
+ is not already dead, clear *INFOP and return 0. If successful, store
+ exit code and status in *INFOP.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int waitid (idtype_t __idtype, __id_t __id, siginfo_t *__infop,
+ int __options);
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* This being here makes the prototypes valid whether or not
+ we have already included <sys/resource.h> to define `struct rusage'. */
+struct rusage;
+
+/* Wait for a child to exit. When one does, put its status in *STAT_LOC and
+ return its process ID. For errors return (pid_t) -1. If USAGE is not
+ nil, store information about the child's resource usage there. If the
+ WUNTRACED bit is set in OPTIONS, return status for stopped children;
+ otherwise don't. */
+extern __pid_t wait3 (__WAIT_STATUS __stat_loc, int __options,
+ struct rusage * __usage) __THROW;
+#endif
+
+#ifdef __USE_BSD
+/* This being here makes the prototypes valid whether or not
+ we have already included <sys/resource.h> to define `struct rusage'. */
+struct rusage;
+
+/* PID is like waitpid. Other args are like wait3. */
+extern __pid_t wait4 (__pid_t __pid, __WAIT_STATUS __stat_loc, int __options,
+ struct rusage *__usage) __THROW;
+#endif /* Use BSD. */
+
+
+__END_DECLS
+
+#endif /* sys/wait.h */
diff --git a/libc/posix/sysconf.c b/libc/posix/sysconf.c
new file mode 100644
index 000000000..f22685cb2
--- /dev/null
+++ b/libc/posix/sysconf.c
@@ -0,0 +1,273 @@
+/* Copyright (C) 1991,1993,1995-1997,2001,2002,2003
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/sysinfo.h>
+
+
+/* Get the value of the system variable NAME. */
+long int
+__sysconf (name)
+ int name;
+{
+ switch (name)
+ {
+ default:
+ __set_errno (EINVAL);
+ return -1;
+
+ case _SC_TZNAME_MAX:
+ return MAX (__tzname_max (), _POSIX_TZNAME_MAX);
+
+ case _SC_CHARCLASS_NAME_MAX:
+#ifdef CHARCLASS_NAME_MAX
+ return CHARCLASS_NAME_MAX;
+#else
+ return -1;
+#endif
+
+ case _SC_COLL_WEIGHTS_MAX:
+#ifdef COLL_WEIGHTS_MAX
+ return COLL_WEIGHTS_MAX;
+#else
+ return -1;
+#endif
+
+ case _SC_EQUIV_CLASS_MAX:
+#ifdef EQUIV_CLASS_MAX
+ return EQUIV_CLASS_MAX;
+#else
+ return -1;
+#endif
+
+ case _SC_2_LOCALEDEF:
+#ifdef _POSIX2_LOCALEDEF
+ return _POSIX2_LOCALEDEF;
+#else
+ return -1;
+#endif
+
+ case _SC_NPROCESSORS_CONF:
+ return __get_nprocs_conf ();
+
+ case _SC_NPROCESSORS_ONLN:
+ return __get_nprocs ();
+
+ case _SC_PHYS_PAGES:
+ return __get_phys_pages ();
+
+ case _SC_AVPHYS_PAGES:
+ return __get_avphys_pages ();
+
+ case _SC_ATEXIT_MAX:
+ /* We have no limit since we use lists. */
+ return INT_MAX;
+
+ case _SC_PASS_MAX:
+ /* We have no limit but since the return value might be used to
+ allocate a buffer we restrict the value. */
+ return BUFSIZ;
+
+ case _SC_CHAR_BIT:
+ return CHAR_BIT;
+
+ case _SC_CHAR_MAX:
+ return CHAR_MAX;
+
+ case _SC_CHAR_MIN:
+ return CHAR_MIN;
+
+ case _SC_INT_MAX:
+ return INT_MAX;
+
+ case _SC_INT_MIN:
+ return INT_MIN;
+
+ case _SC_LONG_BIT:
+ return sizeof (long int) * CHAR_BIT;
+
+ case _SC_WORD_BIT:
+ return sizeof (int) * CHAR_BIT;
+
+ case _SC_MB_LEN_MAX:
+ return MB_LEN_MAX;
+
+ case _SC_NZERO:
+ return NZERO;
+
+ case _SC_SSIZE_MAX:
+ return _POSIX_SSIZE_MAX;
+
+ case _SC_SCHAR_MAX:
+ return SCHAR_MAX;
+
+ case _SC_SCHAR_MIN:
+ return SCHAR_MIN;
+
+ case _SC_SHRT_MAX:
+ return SHRT_MAX;
+
+ case _SC_SHRT_MIN:
+ return SHRT_MIN;
+
+ case _SC_UCHAR_MAX:
+ return UCHAR_MAX;
+
+ case _SC_UINT_MAX:
+ return UINT_MAX;
+
+ case _SC_ULONG_MAX:
+ return ULONG_MAX;
+
+ case _SC_USHRT_MAX:
+ return USHRT_MAX;
+
+ case _SC_GETGR_R_SIZE_MAX:
+ return NSS_BUFLEN_GROUP;
+
+ case _SC_GETPW_R_SIZE_MAX:
+ return NSS_BUFLEN_PASSWD;
+
+ case _SC_ARG_MAX:
+ case _SC_CHILD_MAX:
+ case _SC_CLK_TCK:
+ case _SC_NGROUPS_MAX:
+ case _SC_OPEN_MAX:
+ case _SC_STREAM_MAX:
+ case _SC_JOB_CONTROL:
+ case _SC_SAVED_IDS:
+ case _SC_REALTIME_SIGNALS:
+ case _SC_PRIORITY_SCHEDULING:
+ case _SC_TIMERS:
+ case _SC_ASYNCHRONOUS_IO:
+ case _SC_PRIORITIZED_IO:
+ case _SC_SYNCHRONIZED_IO:
+ case _SC_FSYNC:
+ case _SC_MAPPED_FILES:
+ case _SC_MEMLOCK:
+ case _SC_MEMLOCK_RANGE:
+ case _SC_MEMORY_PROTECTION:
+ case _SC_MESSAGE_PASSING:
+ case _SC_SEMAPHORES:
+ case _SC_SHARED_MEMORY_OBJECTS:
+
+ case _SC_AIO_LISTIO_MAX:
+ case _SC_AIO_MAX:
+ case _SC_AIO_PRIO_DELTA_MAX:
+ case _SC_DELAYTIMER_MAX:
+ case _SC_MQ_OPEN_MAX:
+ case _SC_MQ_PRIO_MAX:
+ case _SC_VERSION:
+ case _SC_PAGESIZE:
+ case _SC_RTSIG_MAX:
+ case _SC_SEM_NSEMS_MAX:
+ case _SC_SEM_VALUE_MAX:
+ case _SC_SIGQUEUE_MAX:
+ case _SC_TIMER_MAX:
+
+ case _SC_PII:
+ case _SC_PII_XTI:
+ case _SC_PII_SOCKET:
+ case _SC_PII_OSI:
+ case _SC_POLL:
+ case _SC_SELECT:
+ case _SC_UIO_MAXIOV:
+ case _SC_PII_INTERNET_STREAM:
+ case _SC_PII_INTERNET_DGRAM:
+ case _SC_PII_OSI_COTS:
+ case _SC_PII_OSI_CLTS:
+ case _SC_PII_OSI_M:
+ case _SC_T_IOV_MAX:
+
+ case _SC_BC_BASE_MAX:
+ case _SC_BC_DIM_MAX:
+ case _SC_BC_SCALE_MAX:
+ case _SC_BC_STRING_MAX:
+ case _SC_EXPR_NEST_MAX:
+ case _SC_LINE_MAX:
+ case _SC_RE_DUP_MAX:
+ case _SC_2_VERSION:
+ case _SC_2_C_BIND:
+ case _SC_2_C_DEV:
+ case _SC_2_FORT_DEV:
+ case _SC_2_SW_DEV:
+ case _SC_2_CHAR_TERM:
+ case _SC_2_C_VERSION:
+ case _SC_2_UPE:
+
+ case _SC_THREADS:
+ case _SC_THREAD_SAFE_FUNCTIONS:
+ case _SC_LOGIN_NAME_MAX:
+ case _SC_TTY_NAME_MAX:
+ case _SC_THREAD_DESTRUCTOR_ITERATIONS:
+ case _SC_THREAD_KEYS_MAX:
+ case _SC_THREAD_STACK_MIN:
+ case _SC_THREAD_THREADS_MAX:
+ case _SC_THREAD_ATTR_STACKADDR:
+ case _SC_THREAD_ATTR_STACKSIZE:
+ case _SC_THREAD_PRIORITY_SCHEDULING:
+ case _SC_THREAD_PRIO_INHERIT:
+ case _SC_THREAD_PRIO_PROTECT:
+ case _SC_THREAD_PROCESS_SHARED:
+
+ case _SC_XOPEN_VERSION:
+ case _SC_XOPEN_XCU_VERSION:
+ case _SC_XOPEN_UNIX:
+ case _SC_XOPEN_CRYPT:
+ case _SC_XOPEN_ENH_I18N:
+ case _SC_XOPEN_SHM:
+ case _SC_XOPEN_XPG2:
+ case _SC_XOPEN_XPG3:
+ case _SC_XOPEN_XPG4:
+
+ case _SC_NL_ARGMAX:
+ case _SC_NL_LANGMAX:
+ case _SC_NL_MSGMAX:
+ case _SC_NL_NMAX:
+ case _SC_NL_SETMAX:
+ case _SC_NL_TEXTMAX:
+
+ case _SC_XBS5_ILP32_OFF32:
+ case _SC_XBS5_ILP32_OFFBIG:
+ case _SC_XBS5_LP64_OFF64:
+ case _SC_XBS5_LPBIG_OFFBIG:
+
+ case _SC_XOPEN_LEGACY:
+ case _SC_XOPEN_REALTIME:
+ case _SC_XOPEN_REALTIME_THREADS:
+
+ break;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+weak_alias (__sysconf, sysconf)
+libc_hidden_def (__sysconf)
+
+stub_warning (sysconf)
+#include <stub-tag.h>
diff --git a/libc/posix/tar.h b/libc/posix/tar.h
new file mode 100644
index 000000000..ddfef755d
--- /dev/null
+++ b/libc/posix/tar.h
@@ -0,0 +1,108 @@
+/* Extended tar format from POSIX.1.
+ Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by David J. MacKenzie.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _TAR_H
+#define _TAR_H 1
+
+/* A tar archive consists of 512-byte blocks.
+ Each file in the archive has a header block followed by 0+ data blocks.
+ Two blocks of NUL bytes indicate the end of the archive. */
+
+/* The fields of header blocks:
+ All strings are stored as ISO 646 (approximately ASCII) strings.
+
+ Fields are numeric unless otherwise noted below; numbers are ISO 646
+ representations of octal numbers, with leading zeros as needed.
+
+ linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix;
+ files that are links to pathnames >100 chars long can not be stored
+ in a tar archive.
+
+ If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0.
+
+ devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}.
+
+ chksum contains the sum of all 512 bytes in the header block,
+ treating each byte as an 8-bit unsigned value and treating the
+ 8 bytes of chksum as blank characters.
+
+ uname and gname are used in preference to uid and gid, if those
+ names exist locally.
+
+ Field Name Byte Offset Length in Bytes Field Type
+ name 0 100 NUL-terminated if NUL fits
+ mode 100 8
+ uid 108 8
+ gid 116 8
+ size 124 12
+ mtime 136 12
+ chksum 148 8
+ typeflag 156 1 see below
+ linkname 157 100 NUL-terminated if NUL fits
+ magic 257 6 must be TMAGIC (NUL term.)
+ version 263 2 must be TVERSION
+ uname 265 32 NUL-terminated
+ gname 297 32 NUL-terminated
+ devmajor 329 8
+ devminor 337 8
+ prefix 345 155 NUL-terminated if NUL fits
+
+ If the first character of prefix is '\0', the file name is name;
+ otherwise, it is prefix/name. Files whose pathnames don't fit in that
+ length can not be stored in a tar archive. */
+
+/* The bits in mode: */
+#define TSUID 04000
+#define TSGID 02000
+#define TSVTX 01000
+#define TUREAD 00400
+#define TUWRITE 00200
+#define TUEXEC 00100
+#define TGREAD 00040
+#define TGWRITE 00020
+#define TGEXEC 00010
+#define TOREAD 00004
+#define TOWRITE 00002
+#define TOEXEC 00001
+
+/* The values for typeflag:
+ Values 'A'-'Z' are reserved for custom implementations.
+ All other values are reserved for future POSIX.1 revisions. */
+
+#define REGTYPE '0' /* Regular file (preferred code). */
+#define AREGTYPE '\0' /* Regular file (alternate code). */
+#define LNKTYPE '1' /* Hard link. */
+#define SYMTYPE '2' /* Symbolic link (hard if not supported). */
+#define CHRTYPE '3' /* Character special. */
+#define BLKTYPE '4' /* Block special. */
+#define DIRTYPE '5' /* Directory. */
+#define FIFOTYPE '6' /* Named pipe. */
+#define CONTTYPE '7' /* Contiguous file */
+ /* (regular file if not supported). */
+
+/* Contents of magic field and its length. */
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+
+/* Contents of the version field and its length. */
+#define TVERSION "00"
+#define TVERSLEN 2
+
+#endif /* tar.h */
diff --git a/libc/posix/test-vfork.c b/libc/posix/test-vfork.c
new file mode 100644
index 000000000..c4904e36e
--- /dev/null
+++ b/libc/posix/test-vfork.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+void __attribute_noinline__ noop (void);
+
+#define NR 2 /* Exit code of the child. */
+
+int
+main (void)
+{
+ pid_t pid;
+ int status;
+
+ printf ("Before vfork\n");
+ fflush (stdout);
+ pid = vfork ();
+ if (pid == 0)
+ {
+ /* This will clobber the return pc from vfork in the parent on
+ machines where it is stored on the stack, if vfork wasn't
+ implemented correctly, */
+ noop ();
+ _exit (NR);
+ }
+ else if (pid < 0)
+ error (1, errno, "vfork");
+ printf ("After vfork (parent)\n");
+ if (waitpid (0, &status, 0) != pid
+ || !WIFEXITED (status) || WEXITSTATUS (status) != NR)
+ exit (1);
+
+ return 0;
+}
+
+void
+noop ()
+{
+}
diff --git a/libc/posix/testcases.h b/libc/posix/testcases.h
new file mode 100644
index 000000000..834f53049
--- /dev/null
+++ b/libc/posix/testcases.h
@@ -0,0 +1,167 @@
+ {0, "(.*)*\\1", "xx"},
+ {0, "^", ""},
+ {0, "$", ""},
+ {0, "^$", ""},
+ {0, "^a$", "a"},
+ {0, "abc", "abc"},
+ {1, "abc", "xbc"},
+ {1, "abc", "axc"},
+ {1, "abc", "abx"},
+ {0, "abc", "xabcy"},
+ {0, "abc", "ababc"},
+ {0, "ab*c", "abc"},
+ {0, "ab*bc", "abc"},
+ {0, "ab*bc", "abbc"},
+ {0, "ab*bc", "abbbbc"},
+ {0, "ab+bc", "abbc"},
+ {1, "ab+bc", "abc"},
+ {1, "ab+bc", "abq"},
+ {0, "ab+bc", "abbbbc"},
+ {0, "ab?bc", "abbc"},
+ {0, "ab?bc", "abc"},
+ {1, "ab?bc", "abbbbc"},
+ {0, "ab?c", "abc"},
+ {0, "^abc$", "abc"},
+ {1, "^abc$", "abcc"},
+ {0, "^abc", "abcc"},
+ {1, "^abc$", "aabc"},
+ {0, "abc$", "aabc"},
+ {0, "^", "abc"},
+ {0, "$", "abc"},
+ {0, "a.c", "abc"},
+ {0, "a.c", "axc"},
+ {0, "a.*c", "axyzc"},
+ {1, "a.*c", "axyzd"},
+ {1, "a[bc]d", "abc"},
+ {0, "a[bc]d", "abd"},
+ {1, "a[b-d]e", "abd"},
+ {0, "a[b-d]e", "ace"},
+ {0, "a[b-d]", "aac"},
+ {0, "a[-b]", "a-"},
+ {0, "a[b-]", "a-"},
+ {2, "a[b-a]", "-"},
+ {2, "a[]b", "-"},
+ {2, "a[", "-"},
+ {0, "a]", "a]"},
+ {0, "a[]]b", "a]b"},
+ {0, "a[^bc]d", "aed"},
+ {1, "a[^bc]d", "abd"},
+ {0, "a[^-b]c", "adc"},
+ {1, "a[^-b]c", "a-c"},
+ {1, "a[^]b]c", "a]c"},
+ {0, "a[^]b]c", "adc"},
+ {0, "ab|cd", "abc"},
+ {0, "ab|cd", "abcd"},
+ {0, "()ef", "def"},
+ {0, "()*", "-"},
+ {2, "*a", "-"},
+ {2, "^*", "-"},
+ {2, "$*", "-"},
+ {2, "(*)b", "-"},
+ {1, "$b", "b"},
+ {2, "a\\", "-"},
+ {0, "a\\(b", "a(b"},
+ {0, "a\\(*b", "ab"},
+ {0, "a\\(*b", "a((b"},
+ {1, "a\\x", "a\\x"},
+ {1, "abc)", "-"},
+ {2, "(abc", "-"},
+ {0, "((a))", "abc"},
+ {0, "(a)b(c)", "abc"},
+ {0, "a+b+c", "aabbabc"},
+ {0, "a**", "-"},
+ {0, "a*?", "-"},
+ {0, "(a*)*", "-"},
+ {0, "(a*)+", "-"},
+ {0, "(a|)*", "-"},
+ {0, "(a*|b)*", "-"},
+ {0, "(a+|b)*", "ab"},
+ {0, "(a+|b)+", "ab"},
+ {0, "(a+|b)?", "ab"},
+ {0, "[^ab]*", "cde"},
+ {0, "(^)*", "-"},
+ {0, "(ab|)*", "-"},
+ {2, ")(", "-"},
+ {1, "abc", ""},
+ {1, "abc", ""},
+ {0, "a*", ""},
+ {0, "([abc])*d", "abbbcd"},
+ {0, "([abc])*bcd", "abcd"},
+ {0, "a|b|c|d|e", "e"},
+ {0, "(a|b|c|d|e)f", "ef"},
+ {0, "((a*|b))*", "-"},
+ {0, "abcd*efg", "abcdefg"},
+ {0, "ab*", "xabyabbbz"},
+ {0, "ab*", "xayabbbz"},
+ {0, "(ab|cd)e", "abcde"},
+ {0, "[abhgefdc]ij", "hij"},
+ {1, "^(ab|cd)e", "abcde"},
+ {0, "(abc|)ef", "abcdef"},
+ {0, "(a|b)c*d", "abcd"},
+ {0, "(ab|ab*)bc", "abc"},
+ {0, "a([bc]*)c*", "abc"},
+ {0, "a([bc]*)(c*d)", "abcd"},
+ {0, "a([bc]+)(c*d)", "abcd"},
+ {0, "a([bc]*)(c+d)", "abcd"},
+ {0, "a[bcd]*dcdcde", "adcdcde"},
+ {1, "a[bcd]+dcdcde", "adcdcde"},
+ {0, "(ab|a)b*c", "abc"},
+ {0, "((a)(b)c)(d)", "abcd"},
+ {0, "[A-Za-z_][A-Za-z0-9_]*", "alpha"},
+ {0, "^a(bc+|b[eh])g|.h$", "abh"},
+ {0, "(bc+d$|ef*g.|h?i(j|k))", "effgz"},
+ {0, "(bc+d$|ef*g.|h?i(j|k))", "ij"},
+ {1, "(bc+d$|ef*g.|h?i(j|k))", "effg"},
+ {1, "(bc+d$|ef*g.|h?i(j|k))", "bcdd"},
+ {0, "(bc+d$|ef*g.|h?i(j|k))", "reffgz"},
+ {1, "((((((((((a))))))))))", "-"},
+ {0, "(((((((((a)))))))))", "a"},
+ {1, "multiple words of text", "uh-uh"},
+ {0, "multiple words", "multiple words, yeah"},
+ {0, "(.*)c(.*)", "abcde"},
+ {1, "\\((.*),", "(.*)\\)"},
+ {1, "[k]", "ab"},
+ {0, "abcd", "abcd"},
+ {0, "a(bc)d", "abcd"},
+ {0, "a[-]?c", "ac"},
+ {0, "(....).*\\1", "beriberi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Qaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mo'ammar Gadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Kaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Qadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moammar El Kadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Gadafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar al-Qadafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moamer El Kazzafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moamar al-Gaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar Al Qathafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Al Qathafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mo'ammar el-Gadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moamar El Kadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar al-Qadhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar al-Qadhdhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar Qadafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moamar Gaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar Qadhdhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Khaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar al-Khaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'amar al-Kadafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Ghaddafy"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Ghadafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Ghaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muamar Kaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Quathafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muammar Gheddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Muamar Al-Kaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moammar Khadafy "},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Moammar Qudhafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mu'ammar al-Qaddafi"},
+ {0, "M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", "Mulazim Awwal Mu'ammar Muhammad Abu Minyar al-Qadhafi"},
+ {0, "[[:digit:]]+", "01234"},
+ {1, "[[:alpha:]]+", "01234"},
+ {0, "^[[:digit:]]*$", "01234"},
+ {1, "^[[:digit:]]*$", "01234a"},
+ {0, "^[[:alnum:]]*$", "01234a"},
+ {0, "^[[:xdigit:]]*$", "01234a"},
+ {1, "^[[:xdigit:]]*$", "01234g"},
+ {0, "^[[:alnum:][:space:]]*$", "Hello world"},
diff --git a/libc/posix/testfnm.c b/libc/posix/testfnm.c
new file mode 100644
index 000000000..f3165324e
--- /dev/null
+++ b/libc/posix/testfnm.c
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "fnmatch.h"
+
+struct {
+ const char *name;
+ const char *pattern;
+ int flags;
+ int expected;
+} tests[] = {
+ { "lib", "*LIB*", FNM_PERIOD, FNM_NOMATCH },
+ { "lib", "*LIB*", FNM_CASEFOLD|FNM_PERIOD, 0 },
+ { "a/b", "a[/]b", 0, 0 },
+ { "a/b", "a[/]b", FNM_PATHNAME, FNM_NOMATCH },
+ { "a/b", "[a-z]/[a-z]", 0, 0 },
+ { "a/b", "*", FNM_PATHNAME, FNM_NOMATCH },
+ { "a/b", "*[/]b", FNM_PATHNAME, FNM_NOMATCH },
+ { "a/b", "*[b]", FNM_PATHNAME, FNM_NOMATCH },
+ { "a/b", "[*]/b", 0, FNM_NOMATCH },
+ { "*/b", "[*]/b", 0, 0 },
+ { "a/b", "[?]/b", 0, FNM_NOMATCH },
+ { "?/b", "[?]/b", 0, 0 },
+ { "a/b", "[[a]/b", 0, 0 },
+ { "[/b", "[[a]/b", 0, 0 },
+ { "a/b", "\\*/b", 0, FNM_NOMATCH },
+ { "*/b", "\\*/b", 0, 0 },
+ { "a/b", "\\?/b", 0, FNM_NOMATCH },
+ { "?/b", "\\?/b", 0, 0 },
+ { "[/b", "[/b", 0, FNM_NOMATCH },
+ { "[/b", "\\[/b", 0, 0 },
+ { "aa/b", "?""?/b", 0, 0 },
+ { "aa/b", "?""?""?b", 0, 0 },
+ { "aa/b", "?""?""?b", FNM_PATHNAME, FNM_NOMATCH },
+ { ".a/b", "?a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/?b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { ".a/b", "*a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/*b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { ".a/b", "[.]a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/[.]b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/b", "*/?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/b", "?/*", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { ".a/b", ".*/?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/.b", "*/.?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/.b", "*/*", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "*?*/*", FNM_PERIOD, 0 },
+ { "a./b", "*[.]/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/b", "*[[:alpha:]]/*[[:alnum:]]", FNM_PATHNAME, 0 },
+ { "a/b", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, 0 },
+ { "a/[", "*[![:digit:]]*/[[:d-d]", FNM_PATHNAME, 0 },
+ { "a/[", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, FNM_NOMATCH },
+ { "a.b", "a?b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a.b", "a*b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a.b", "a[.]b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/b", "*a*", FNM_PATHNAME|FNM_LEADING_DIR, 0 },
+ { "ab/c", "*a?", FNM_PATHNAME|FNM_LEADING_DIR, 0 },
+ { "ab/c", "a?", FNM_PATHNAME|FNM_LEADING_DIR, 0 },
+ { "a/b", "?*/?", FNM_PATHNAME, 0 },
+ { "/b", "*/?", FNM_PATHNAME, 0 },
+ { "/b", "**/?", FNM_PATHNAME, 0 },
+};
+
+int
+main (void)
+{
+ size_t i;
+ int errors = 0;
+
+ for (i = 0; i < sizeof (tests) / sizeof (*tests); i++)
+ {
+ int match;
+
+ match = fnmatch (tests[i].pattern, tests[i].name, tests[i].flags);
+
+ printf ("[%2zd] %s %s %s -> %s\n", i, tests[i].pattern,
+ match == 0 ? "matches" : "does not match",
+ tests[i].name,
+ match != tests[i].expected ? "FAIL" : "OK");
+
+ if (match != tests[i].expected)
+ ++errors ;
+ }
+
+ return errors != 0;
+}
diff --git a/libc/posix/times.c b/libc/posix/times.c
new file mode 100644
index 000000000..b4e08156a
--- /dev/null
+++ b/libc/posix/times.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/times.h>
+#include <stddef.h>
+
+/* Store the CPU time used by this process and all its
+ dead children (and their dead children) in BUFFER.
+ Return the elapsed real time, or (clock_t) -1 for errors.
+ All times are in CLK_TCKths of a second. */
+clock_t
+__times (buffer)
+ struct tms *buffer;
+{
+ if (buffer == NULL)
+ {
+ __set_errno (EINVAL);
+ return (clock_t) -1;
+ }
+
+ __set_errno (ENOSYS);
+ return (clock_t) -1;
+}
+stub_warning (times)
+
+weak_alias (__times, times)
+#include <stub-tag.h>
diff --git a/libc/posix/transbug.c b/libc/posix/transbug.c
new file mode 100755
index 000000000..d0983b4d4
--- /dev/null
+++ b/libc/posix/transbug.c
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+/* lowercase chars mapped to uppercase */
+static const char casetable[] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ /* ' ' '!' '"' '#' '$' '%' '&' ''' */
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ /* '(' ')' '*' '+' ',' '-' '.' '/' */
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ /* '0' '1' '2' '3' '4' '5' '6' '7' */
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ /* '8' '9' ':' ';' '<' '=' '>' '?' */
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ /* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ /* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ /* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ /* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ /* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ /* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ /* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ /* 'x' 'y' 'z' '{' '|' '}' '~' */
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+
+ /* Latin 1: */
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+
+static int
+run_test (const char *pattern, struct re_registers *regs)
+{
+ static char text[] = "1111AAAA2222bbbb";
+
+ struct re_pattern_buffer pat;
+
+ const char *err;
+ int res;
+ int start2;
+
+ memset (&pat, '\0', sizeof (pat));
+ memset (regs, '\0', 2 * sizeof (regs[0]));
+ pat.allocated = 0; /* regex will allocate the buffer */
+ pat.fastmap = (char *) malloc (256);
+ if (pat.fastmap == NULL)
+ {
+ puts ("out of memory");
+ exit (1);
+ }
+
+ pat.translate = (unsigned char *) casetable;
+
+ err = re_compile_pattern (pattern, strlen (pattern), &pat);
+ if (err != NULL)
+ {
+ fprintf (stderr, "/%s/: %s\n", pattern, err);
+ exit (1);
+ }
+ res = re_search (&pat, text, strlen (text), 0, strlen (text), &regs[0]);
+ if (res < 0)
+ printf ("search 1: res = %d\n", res);
+ else
+ printf ("search 1: res = %d, start = %d, end = %d\n",
+ res, regs[0].start[0], regs[0].end[0]);
+
+ if (regs[0].end == NULL)
+ start2 = 8;
+ else
+ start2 = regs[0].end[0] + 1;
+ regs[1] = regs[0];
+ res = re_search (&pat, text, strlen (text), start2, strlen (text), &regs[1]);
+ if (res < 0)
+ printf ("search 2: res = %d\n", res);
+ else
+ printf ("search 2: res = %d, start = %d, end = %d\n",
+ res, regs[1].start[0], regs[1].end[0]);
+
+ return res < 0 ? 1 : 0;
+}
+
+
+static int
+do_test (void)
+{
+ static const char lower[] = "[[:lower:]]+";
+ static const char upper[] = "[[:upper:]]+";
+ struct re_registers regs[4];
+
+ setlocale (LC_ALL, "C");
+
+ (void) re_set_syntax (RE_SYNTAX_GNU_AWK);
+
+ int result;
+#define CHECK(exp) \
+ if (exp) { puts (#exp); result = 1; }
+
+ result = run_test (lower, regs);
+ result |= run_test (upper, &regs[2]);
+ if (! result)
+ {
+ CHECK (regs[0].start[0] != regs[2].start[0]);
+ CHECK (regs[0].end[0] != regs[2].end[0]);
+ CHECK (regs[1].start[0] != regs[3].start[0]);
+ CHECK (regs[1].end[0] != regs[3].end[0]);
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-boost.c b/libc/posix/tst-boost.c
new file mode 100644
index 000000000..8446a2e54
--- /dev/null
+++ b/libc/posix/tst-boost.c
@@ -0,0 +1,227 @@
+/* Regular expression tests.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+frob_escapes (char *src, int pattern)
+{
+ char *dst;
+
+ for (dst = src; *src != '\0'; dst++, src++)
+ {
+ if (*src == '\\')
+ {
+ switch (src[1])
+ {
+ case 't':
+ src++;
+ *dst = '\t';
+ continue;
+ case 'n':
+ src++;
+ *dst = '\n';
+ continue;
+ case 'r':
+ src++;
+ *dst = '\r';
+ continue;
+ case '\\':
+ case '^':
+ case '{':
+ case '|':
+ case '}':
+ if (!pattern)
+ {
+ src++;
+ *dst = *src;
+ continue;
+ }
+ break;
+ }
+ }
+ if (src != dst)
+ *dst = *src;
+ }
+ *dst = '\0';
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0, n;
+ char *line = NULL;
+ size_t line_len = 0;
+ ssize_t len;
+ FILE *f;
+ char *pattern, *string;
+ int flags = REG_EXTENDED;
+ int eflags = 0;
+ regex_t re;
+ regmatch_t rm[20];
+
+ mtrace ();
+
+ if (argc < 2)
+ {
+ fprintf (stderr, "Missing test filename\n");
+ return 1;
+ }
+
+ f = fopen (argv[1], "r");
+ if (f == NULL)
+ {
+ fprintf (stderr, "Couldn't open %s\n", argv[1]);
+ return 1;
+ }
+
+ while ((len = getline (&line, &line_len, f)) > 0)
+ {
+ char *p, *q;
+ int i;
+
+ if (line[len - 1] == '\n')
+ line[--len] = '\0';
+
+ puts (line);
+
+ if (line[0] == ';')
+ continue;
+
+ if (line[0] == '\0')
+ continue;
+
+ if (line[0] == '-')
+ {
+ if (strstr (line, "REG_BASIC"))
+ flags = 0;
+ else
+ flags = REG_EXTENDED;
+ if (strstr (line, "REG_ICASE"))
+ flags |= REG_ICASE;
+ if (strstr (line, "REG_NEWLINE"))
+ flags |= REG_NEWLINE;
+ eflags = 0;
+ if (strstr (line, "REG_NOTBOL"))
+ eflags |= REG_NOTBOL;
+ if (strstr (line, "REG_NOTEOL"))
+ eflags |= REG_NOTEOL;
+ continue;
+ }
+
+ pattern = line + strspn (line, " \t");
+ if (*pattern == '\0')
+ continue;
+ p = pattern + strcspn (pattern, " \t");
+ if (*p == '\0')
+ continue;
+ *p++ = '\0';
+
+ string = p + strspn (p, " \t");
+ if (*string == '\0')
+ continue;
+ if (*string == '"')
+ {
+ string++;
+ p = strchr (string, '"');
+ if (p == NULL)
+ continue;
+ *p++ = '\0';
+ }
+ else
+ {
+ p = string + strcspn (string, " \t");
+ if (*string == '!')
+ string = NULL;
+ else if (*p == '\0')
+ continue;
+ else
+ *p++ = '\0';
+ }
+
+ frob_escapes (pattern, 1);
+ if (string != NULL)
+ frob_escapes (string, 0);
+
+ n = regcomp (&re, pattern, flags);
+ if (n != 0)
+ {
+ if (string != NULL)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("FAIL regcomp unexpectedly failed: %s\n",
+ buf);
+ ret = 1;
+ }
+ continue;
+ }
+ else if (string == NULL)
+ {
+ regfree (&re);
+ puts ("FAIL regcomp unpexpectedly succeeded");
+ ret = 1;
+ continue;
+ }
+
+ if (regexec (&re, string, 20, rm, eflags))
+ {
+ for (i = 0; i < 20; ++i)
+ {
+ rm[i].rm_so = -1;
+ rm[i].rm_eo = -1;
+ }
+ }
+
+ regfree (&re);
+
+ for (i = 0; i < 20 && *p != '\0'; ++i)
+ {
+ int rm_so, rm_eo;
+
+ rm_so = strtol (p, &q, 10);
+ if (p == q)
+ break;
+ p = q;
+
+ rm_eo = strtol (p, &q, 10);
+ if (p == q)
+ break;
+ p = q;
+
+ if (rm[i].rm_so != rm_so || rm[i].rm_eo != rm_eo)
+ {
+ printf ("FAIL rm[%d] %d..%d != expected %d..%d\n",
+ i, rm[i].rm_so, rm[i].rm_eo, rm_so, rm_eo);
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ free (line);
+ fclose (f);
+ return ret;
+}
diff --git a/libc/posix/tst-chmod.c b/libc/posix/tst-chmod.c
new file mode 100644
index 000000000..d37e4820f
--- /dev/null
+++ b/libc/posix/tst-chmod.c
@@ -0,0 +1,378 @@
+/* Test for chmod functions.
+ Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+#define OUT_OF_MEMORY \
+ do { \
+ puts ("cannot allocate memory"); \
+ result = 1; \
+ goto fail; \
+ } while (0)
+
+static int
+do_test (int argc, char *argv[])
+{
+ const char *builddir;
+ struct stat64 st1;
+ struct stat64 st2;
+ char *buf;
+ char *testdir;
+ char *testfile = NULL;
+ char *startdir;
+ size_t buflen;
+ int fd;
+ int result = 0;
+ DIR *dir;
+
+ mtrace ();
+
+ if (argc <= 1)
+ error (EXIT_FAILURE, 0, "no parameters");
+
+ /* This is where we will create the test files. */
+ builddir = argv[1];
+ buflen = strlen (builddir) + 50;
+
+ startdir = getcwd (NULL, 0);
+ if (startdir == NULL)
+ {
+ printf ("cannot get current directory: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* A buffer large enough for everything we need. */
+ buf = (char *) alloca (buflen);
+
+ /* Create the directory name. */
+ snprintf (buf, buflen, "%s/chmoddirXXXXXX", builddir);
+
+ if (mkdtemp (buf) == NULL)
+ {
+ printf ("cannot create test directory: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ if (chmod ("", 0600) == 0)
+ {
+ puts ("chmod(\"\", 0600 didn't fail");
+ result = 1;
+ }
+ else if (errno != ENOENT)
+ {
+ puts ("chmod(\"\",0600) does not set errno to ENOENT");
+ result = 1;
+ }
+
+ /* Create a duplicate. */
+ testdir = strdup (buf);
+ if (testdir == NULL)
+ OUT_OF_MEMORY;
+
+ if (stat64 (testdir, &st1) != 0)
+ {
+ printf ("cannot stat test directory: %m\n");
+ exit (1);
+ }
+ if (!S_ISDIR (st1.st_mode))
+ {
+ printf ("file not created as directory: %m\n");
+ exit (1);
+ }
+
+ /* We have to wait for a second to make sure the ctime changes. */
+ sleep (1);
+
+ /* Remove all access rights from the directory. */
+ if (chmod (testdir, 0) != 0)
+ {
+ printf ("cannot change mode of test directory: %m\n");
+ result = 1;
+ goto fail;
+ }
+
+ if (stat64 (testdir, &st2) != 0)
+ {
+ printf ("cannot stat test directory: %m\n");
+ result = 1;
+ goto fail;
+ }
+
+ /* Compare result. */
+ if ((st2.st_mode & ALLPERMS) != 0)
+ {
+ printf ("chmod(...,0) on directory left bits nonzero: %o\n",
+ st2.st_mode & ALLPERMS);
+ result = 1;
+ }
+ if (st1.st_ctime >= st2.st_ctime)
+ {
+ puts ("chmod(...,0) did not set ctime correctly");
+ result = 1;
+ }
+
+ /* Name of a file in the directory. */
+ snprintf (buf, buflen, "%s/file", testdir);
+ testfile = strdup (buf);
+ if (testfile == NULL)
+ OUT_OF_MEMORY;
+
+ fd = creat (testfile, 0);
+ if (fd != -1)
+ {
+ if (getuid () != 0)
+ {
+ puts ("managed to create test file in protected directory");
+ result = 1;
+ }
+ close (fd);
+ }
+ else if (errno != EACCES)
+ {
+ puts ("creat didn't generate correct errno value");
+ result = 1;
+ }
+
+ /* With this mode it still shouldn't be possible to create a file. */
+ if (chmod (testdir, 0600) != 0)
+ {
+ printf ("cannot change mode of test directory to 0600: %m\n");
+ result = 1;
+ goto fail;
+ }
+
+ fd = creat (testfile, 0);
+ if (fd != -1)
+ {
+ if (getuid () != 0)
+ {
+ puts ("managed to create test file in no-x protected directory");
+ result = 1;
+ }
+ close (fd);
+ }
+ else if (errno != EACCES)
+ {
+ puts ("creat didn't generate correct errno value");
+ result = 1;
+ }
+
+ /* Change the directory mode back to allow creating a file. This
+ time with fchmod. */
+ dir = opendir (testdir);
+ if (dir != NULL)
+ {
+ if (fchmod (dirfd (dir), 0700) != 0)
+ {
+ printf ("cannot change mode of test directory to 0700: %m\n");
+ result = 1;
+ closedir (dir);
+ goto fail;
+ }
+
+ closedir (dir);
+ }
+ else
+ {
+ printf ("cannot open directory: %m\n");
+ result = 1;
+
+ if (chmod (testdir, 0700) != 0)
+ {
+ printf ("cannot change mode of test directory to 0700: %m\n");
+ goto fail;
+ }
+ }
+
+ fd = creat (testfile, 0);
+ if (fd == -1)
+ {
+ puts ("still didn't manage to create test file in protected directory");
+ result = 1;
+ goto fail;
+ }
+ if (fstat64 (fd, &st1) != 0)
+ {
+ printf ("cannot stat new file: %m\n");
+ result = 1;
+ }
+ else if ((st1.st_mode & ALLPERMS) != 0)
+ {
+ puts ("file not created with access mode 0");
+ result = 1;
+ }
+ close (fd);
+
+ snprintf (buf, buflen, "%s/..", testdir);
+ chdir (buf);
+ /* We are now in the directory above the one we create the test
+ directory in. */
+
+ sleep (1);
+ snprintf (buf, buflen, "./%s/../%s/file",
+ basename (testdir), basename (testdir));
+ if (chmod (buf, 0600) != 0)
+ {
+ printf ("cannot change mode of file to 0600: %m\n");
+ result = 1;
+ goto fail;
+ }
+ snprintf (buf, buflen, "./%s//file", basename (testdir));
+ if (stat64 (buf, &st2) != 0)
+ {
+ printf ("cannot stat new file: %m\n");
+ result = 1;
+ }
+ else if ((st2.st_mode & ALLPERMS) != 0600)
+ {
+ puts ("file mode not changed to 0600");
+ result = 1;
+ }
+ else if (st1.st_ctime >= st2.st_ctime)
+ {
+ puts ("chmod(\".../file\",0600) did not set ctime correctly");
+ result = 1;
+ }
+
+ if (chmod (buf, 0777 | S_ISUID | S_ISGID) != 0)
+ {
+ printf ("cannot change mode of file to %o: %m\n",
+ 0777 | S_ISUID | S_ISGID);
+ result = 1;
+ }
+ if (stat64 (buf, &st2) != 0)
+ {
+ printf ("cannot stat test file: %m\n");
+ result = 1;
+ }
+ else if ((st2.st_mode & ALLPERMS) != (0777 | S_ISUID | S_ISGID))
+ {
+ puts ("file mode not changed to 0777 | S_ISUID | S_ISGID");
+ result = 1;
+ }
+
+ if (chmod (basename (testdir), 0777 | S_ISUID | S_ISGID | S_ISVTX) != 0)
+ {
+ printf ("cannot change mode of test directory to %o: %m\n",
+ 0777 | S_ISUID | S_ISGID | S_ISVTX);
+ result = 1;
+ }
+ if (stat64 (basename (testdir), &st2) != 0)
+ {
+ printf ("cannot stat test directory: %m\n");
+ result = 1;
+ }
+ else if ((st2.st_mode & ALLPERMS) != (0777 | S_ISUID | S_ISGID | S_ISVTX))
+ {
+ puts ("directory mode not changed to 0777 | S_ISUID | S_ISGID | S_ISGID");
+ result = 1;
+ }
+
+ snprintf (buf, buflen, "./%s/no-such-file", basename (testdir));
+ if (chmod (buf, 0600) != -1)
+ {
+ puts ("chmod(\".../no-such-file\",0600) did not fail");
+ result = 1;
+ }
+ else if (errno != ENOENT)
+ {
+ puts ("chmod(\".../no-such-file\",0600) does not set errno to ENOENT");
+ result = 1;
+ }
+
+ snprintf (buf, buflen, "%s/", basename (testdir));
+ if (chmod (basename (testdir), 0677) != 0)
+ {
+ printf ("cannot change mode of test directory to 0677: %m\n");
+ result = 1;
+ }
+ else
+ {
+ snprintf (buf, buflen, "./%s/file", basename (testdir));
+ if (chmod (buf, 0600) == 0)
+ {
+ if (getuid () != 0)
+ {
+ puts ("chmod(\".../file\") with no-exec directory succeeded");
+ result = 1;
+ }
+ }
+ else if (errno != EACCES)
+ {
+ puts ("chmod(\".../file\") with no-exec directory didn't set EACCES");
+ result = 1;
+ }
+ }
+
+ if (chmod (basename (testdir), 0777) != 0)
+ {
+ printf ("cannot change mode of test directory to 0777: %m\n");
+ result = 1;
+ goto fail;
+ }
+
+ snprintf (buf, buflen, "%s/file/cannot-be", basename (testdir));
+ if (chmod (buf, 0600) == 0)
+ {
+ puts ("chmod(\".../file/cannot-be\",0600) did not fail");
+ result = 1;
+ }
+ else if (errno != ENOTDIR)
+ {
+ puts ("chmod(\".../file/cannot-be\",0600) does not set errno to ENOTDIR");
+ result = 1;
+ }
+
+ fail:
+ chdir (startdir);
+
+ /* Remove all the files. */
+ chmod (testdir, 0700);
+ if (testfile != NULL)
+ {
+ chmod (testfile, 0700);
+ unlink (testfile);
+ }
+ rmdir (testdir);
+
+ /* Free the resources. */
+ free (testfile);
+ free (testdir);
+ free (startdir);
+
+ return result;
+}
+
+
+/* We need a few seconds since we have a few sleeps in the code. */
+#define TIMEOUT 20
+
+
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-dir.c b/libc/posix/tst-dir.c
new file mode 100644
index 000000000..400849a94
--- /dev/null
+++ b/libc/posix/tst-dir.c
@@ -0,0 +1,571 @@
+/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+/* We expect four arguments:
+ - source directory name
+ - object directory
+ - common object directory
+ - the program name with path
+*/
+int
+main (int argc, char *argv[])
+{
+ const char *srcdir;
+ const char *objdir;
+ const char *common_objdir;
+ const char *progpath;
+ struct stat64 st1;
+ struct stat64 st2;
+ struct stat64 st3;
+ DIR *dir1;
+ DIR *dir2;
+ int result = 0;
+ struct dirent64 *d;
+ union
+ {
+ struct dirent64 d;
+ char room [offsetof (struct dirent64, d_name[0]) + NAME_MAX + 1];
+ }
+ direntbuf;
+ char *objdir_copy1;
+ char *objdir_copy2;
+ char *buf;
+ int fd;
+
+ mtrace ();
+
+ if (argc < 5)
+ {
+ puts ("not enough parameters");
+ exit (1);
+ }
+
+ /* Make parameters available with nicer names. */
+ srcdir = argv[1];
+ objdir = argv[2];
+ common_objdir = argv[3];
+ progpath = argv[4];
+
+ /* First test the current source dir. We cannot really compare the
+ result of `getpwd' with the srcdir string but we have other means. */
+ if (stat64 (".", &st1) < 0)
+ {
+ printf ("cannot stat starting directory: %m\n");
+ exit (1);
+ }
+
+ if (chdir (srcdir) < 0)
+ {
+ printf ("cannot change to source directory: %m\n");
+ exit (1);
+ }
+ if (stat64 (".", &st2) < 0)
+ {
+ printf ("cannot stat source directory: %m\n");
+ exit (1);
+ }
+
+ /* The two last stat64 calls better were for the same directory. */
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("stat of source directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ /* Change to the object directory. */
+ if (chdir (objdir) < 0)
+ {
+ printf ("cannot change to object directory: %m\n");
+ exit (1);
+ }
+ if (stat64 (".", &st1) < 0)
+ {
+ printf ("cannot stat object directory: %m\n");
+ exit (1);
+ }
+ /* Is this the same we get as with the full path? */
+ if (stat64 (objdir, &st2) < 0)
+ {
+ printf ("cannot stat object directory with full path: %m\n");
+ exit (1);
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ objdir_copy1 = getcwd (NULL, 0);
+ if (objdir_copy1 == NULL)
+ {
+ printf ("cannot get current directory name for object directory: %m\n");
+ result = 1;
+ }
+
+ /* First test: this directory must include our program. */
+ if (stat64 (progpath, &st2) < 0)
+ {
+ printf ("cannot stat program: %m\n");
+ exit (1);
+ }
+
+ dir1 = opendir (".");
+ if (dir1 == NULL)
+ {
+ printf ("cannot open object directory: %m\n");
+ exit (1);
+ }
+
+ while ((d = readdir64 (dir1)) != NULL)
+ {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
+ continue;
+#endif
+
+ if (d->d_ino == st2.st_ino)
+ {
+ /* Might be it. Test the device. We could use the st_dev
+ element from st1 but what the heck, do more testing. */
+ if (stat64 (d->d_name, &st3) < 0)
+ {
+ printf ("cannot stat entry from readdir: %m\n");
+ result = 1;
+ d = NULL;
+ break;
+ }
+
+ if (st3.st_dev == st2.st_dev)
+ break;
+ }
+ }
+
+ if (d == NULL)
+ {
+ puts ("haven't found program in object directory");
+ result = 1;
+ }
+
+ /* We leave dir1 open. */
+
+ /* Stat using file descriptor. */
+ if (fstat64 (dirfd (dir1), &st2) < 0)
+ {
+ printf ("cannot fstat object directory: %m\n");
+ result = 1;
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("fstat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ if (chdir ("..") < 0)
+ {
+ printf ("cannot go to common object directory with \"..\": %m\n");
+ exit (1);
+ }
+
+ if (stat64 (".", &st1) < 0)
+ {
+ printf ("cannot stat common object directory: %m\n");
+ exit (1);
+ }
+ /* Is this the same we get as with the full path? */
+ if (stat64 (common_objdir, &st2) < 0)
+ {
+ printf ("cannot stat common object directory with full path: %m\n");
+ exit (1);
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ /* Stat using file descriptor. */
+ if (fstat64 (dirfd (dir1), &st2) < 0)
+ {
+ printf ("cannot fstat object directory: %m\n");
+ result = 1;
+ }
+
+ dir2 = opendir (common_objdir);
+ if (dir2 == NULL)
+ {
+ printf ("cannot open common object directory: %m\n");
+ exit (1);
+ }
+
+ while ((d = readdir64 (dir2)) != NULL)
+ {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
+ continue;
+#endif
+
+ if (d->d_ino == st2.st_ino)
+ {
+ /* Might be it. Test the device. We could use the st_dev
+ element from st1 but what the heck, do more testing. */
+ if (stat64 (d->d_name, &st3) < 0)
+ {
+ printf ("cannot stat entry from readdir: %m\n");
+ result = 1;
+ d = NULL;
+ break;
+ }
+
+ if (st3.st_dev == st2.st_dev)
+ break;
+ }
+ }
+
+ /* This better should be the object directory again. */
+ if (fchdir (dirfd (dir1)) < 0)
+ {
+ printf ("cannot fchdir to object directory: %m\n");
+ exit (1);
+ }
+
+ objdir_copy2 = getcwd (NULL, 0);
+ if (objdir_copy2 == NULL)
+ {
+ printf ("cannot get current directory name for object directory: %m\n");
+ result = 1;
+ }
+ if (strcmp (objdir_copy1, objdir_copy2) != 0)
+ {
+ puts ("getcwd returned a different string the second time");
+ result = 1;
+ }
+
+ /* This better should be the common object directory again. */
+ if (fchdir (dirfd (dir2)) < 0)
+ {
+ printf ("cannot fchdir to common object directory: %m\n");
+ exit (1);
+ }
+
+ if (stat64 (".", &st2) < 0)
+ {
+ printf ("cannot stat common object directory: %m\n");
+ exit (1);
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ buf = (char *) malloc (strlen (objdir_copy1) + 1 + sizeof "tst-dir.XXXXXX");
+ if (buf == NULL)
+ {
+ printf ("cannot allocate buffer: %m");
+ exit (1);
+ }
+
+ stpcpy (stpcpy (stpcpy (buf, objdir_copy1), "/"), "tst-dir.XXXXXX");
+ if (mkdtemp (buf) == NULL)
+ {
+ printf ("cannot create test directory in object directory: %m\n");
+ exit (1);
+ }
+ if (stat64 (buf, &st1) < 0)
+ {
+ printf ("cannot stat new directory \"%s\": %m\n", buf);
+ exit (1);
+ }
+ if (chmod (buf, 0700) < 0)
+ {
+ printf ("cannot change mode of new directory: %m\n");
+ exit (1);
+ }
+
+ /* Try to find the new directory. */
+ rewinddir (dir1);
+ while (readdir64_r (dir1, &direntbuf.d, &d) == 0 && d != NULL)
+ {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
+ continue;
+#endif
+
+ if (d->d_ino == st1.st_ino)
+ {
+ /* Might be it. Test the device. We could use the st_dev
+ element from st1 but what the heck, do more testing. */
+ size_t len = strlen (objdir) + 1 + _D_EXACT_NAMLEN (d) + 1;
+ char tmpbuf[len];
+
+ stpcpy (stpcpy (stpcpy (tmpbuf, objdir), "/"), d->d_name);
+
+ if (stat64 (tmpbuf, &st3) < 0)
+ {
+ printf ("cannot stat entry from readdir: %m\n");
+ result = 1;
+ d = NULL;
+ break;
+ }
+
+ if (st3.st_dev == st2.st_dev
+ && strcmp (d->d_name, buf + strlen (buf) - 14) == 0)
+ break;
+ }
+ }
+
+ if (d == NULL)
+ {
+ printf ("haven't found new directory \"%s\"\n", buf);
+ exit (1);
+ }
+
+ if (closedir (dir2) < 0)
+ {
+ printf ("closing dir2 failed: %m\n");
+ result = 1;
+ }
+
+ if (chdir (buf) < 0)
+ {
+ printf ("cannot change to new directory: %m\n");
+ exit (1);
+ }
+
+ dir2 = opendir (buf);
+ if (dir2 == NULL)
+ {
+ printf ("cannot open new directory: %m\n");
+ exit (1);
+ }
+
+ if (fstat64 (dirfd (dir2), &st2) < 0)
+ {
+ printf ("cannot fstat new directory \"%s\": %m\n", buf);
+ exit (1);
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ printf ("stat of new directory failed: (%lld,%lld) vs (%lld,%lld)\n",
+ (long long int) st1.st_dev, (long long int) st1.st_ino,
+ (long long int) st2.st_dev, (long long int) st2.st_ino);
+ exit (1);
+ }
+
+ if (mkdir ("another-dir", 0777) < 0)
+ {
+ printf ("cannot create \"another-dir\": %m\n");
+ exit (1);
+ }
+ fd = open ("and-a-file", O_RDWR | O_CREAT | O_EXCL, 0666);
+ if (fd == -1)
+ {
+ printf ("cannot create \"and-a-file\": %m\n");
+ exit (1);
+ }
+ close (fd);
+
+ /* Some tests about error reporting. */
+ errno = 0;
+ if (chdir ("and-a-file") >= 0)
+ {
+ printf ("chdir to \"and-a-file\" succeeded\n");
+ exit (1);
+ }
+ if (errno != ENOTDIR)
+ {
+ printf ("chdir to \"and-a-file\" didn't set correct error\n");
+ result = 1;
+ }
+
+ errno = 0;
+ if (chdir ("and-a-file/..") >= 0)
+ {
+ printf ("chdir to \"and-a-file/..\" succeeded\n");
+ exit (1);
+ }
+ if (errno != ENOTDIR)
+ {
+ printf ("chdir to \"and-a-file/..\" didn't set correct error\n");
+ result = 1;
+ }
+
+ errno = 0;
+ if (chdir ("another-dir/../and-a-file") >= 0)
+ {
+ printf ("chdir to \"another-dir/../and-a-file\" succeeded\n");
+ exit (1);
+ }
+ if (errno != ENOTDIR)
+ {
+ printf ("chdir to \"another-dir/../and-a-file\" didn't set correct error\n");
+ result = 1;
+ }
+
+ /* We now should have a directory and a file in the new directory. */
+ rewinddir (dir2);
+ while (readdir64_r (dir2, &direntbuf.d, &d) == 0 && d != NULL)
+ {
+ if (strcmp (d->d_name, ".") == 0
+ || strcmp (d->d_name, "..") == 0
+ || strcmp (d->d_name, "another-dir") == 0)
+ {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
+ {
+ printf ("d_type for \"%s\" is wrong\n", d->d_name);
+ result = 1;
+ }
+#endif
+ if (stat64 (d->d_name, &st3) < 0)
+ {
+ printf ("cannot stat \"%s\" is wrong\n", d->d_name);
+ result = 1;
+ }
+ else if (! S_ISDIR (st3.st_mode))
+ {
+ printf ("\"%s\" is no directory\n", d->d_name);
+ result = 1;
+ }
+ }
+ else if (strcmp (d->d_name, "and-a-file") == 0)
+ {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
+ {
+ printf ("d_type for \"%s\" is wrong\n", d->d_name);
+ result = 1;
+ }
+#endif
+ if (stat64 (d->d_name, &st3) < 0)
+ {
+ printf ("cannot stat \"%s\" is wrong\n", d->d_name);
+ result = 1;
+ }
+ else if (! S_ISREG (st3.st_mode))
+ {
+ printf ("\"%s\" is no regular file\n", d->d_name);
+ result = 1;
+ }
+ }
+ else
+ {
+ printf ("unexpected directory entry \"%s\"\n", d->d_name);
+ result = 1;
+ }
+ }
+
+ if (stat64 ("does-not-exist", &st1) >= 0)
+ {
+ puts ("stat for unexisting file did not fail");
+ result = 1;
+ }
+
+ /* Free all resources. */
+
+ if (closedir (dir1) < 0)
+ {
+ printf ("closing dir1 failed: %m\n");
+ result = 1;
+ }
+ if (closedir (dir2) < 0)
+ {
+ printf ("second closing dir2 failed: %m\n");
+ result = 1;
+ }
+
+ if (rmdir ("another-dir") < 0)
+ {
+ printf ("cannot remove \"another-dir\": %m\n");
+ result = 1;
+ }
+
+ if (unlink ("and-a-file") < 0)
+ {
+ printf ("cannot remove \"and-a-file\": %m\n");
+ result = 1;
+ }
+
+ /* One more test before we leave: mkdir() is supposed to fail with
+ EEXIST if the named file is a symlink. */
+ if (symlink ("a-symlink", "a-symlink") != 0)
+ {
+ printf ("cannot create symlink \"a-symlink\": %m\n");
+ result = 1;
+ }
+ else
+ {
+ if (mkdir ("a-symlink", 0666) == 0)
+ {
+ puts ("can make directory \"a-symlink\"");
+ result = 1;
+ }
+ else if (errno != EEXIST)
+ {
+ puts ("mkdir(\"a-symlink\") does not fail with EEXIST\n");
+ result = 1;
+ }
+ if (unlink ("a-symlink") < 0)
+ {
+ printf ("cannot unlink \"a-symlink\": %m\n");
+ result = 1;
+ }
+ }
+
+ if (chdir (srcdir) < 0)
+ {
+ printf ("cannot change back to source directory: %m\n");
+ exit (1);
+ }
+
+ if (rmdir (buf) < 0)
+ {
+ printf ("cannot remove \"%s\": %m\n", buf);
+ result = 1;
+ }
+ free (objdir_copy1);
+ free (objdir_copy2);
+
+ if (result == 0)
+ puts ("all OK");
+
+ return result;
+}
diff --git a/libc/posix/tst-exec.c b/libc/posix/tst-exec.c
new file mode 100644
index 000000000..a67d2000b
--- /dev/null
+++ b/libc/posix/tst-exec.c
@@ -0,0 +1,210 @@
+/* Tests for exec.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wait.h>
+
+
+/* Nonzero if the program gets called via `exec'. */
+static int restart;
+
+
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+
+/* Prototype for our test function. */
+extern void do_prepare (int argc, char *argv[]);
+extern int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+#define PREPARE do_prepare
+
+#include "../test-skeleton.c"
+
+
+/* Name of the temporary files. */
+static char *name1;
+static char *name2;
+
+/* The contents of our files. */
+static const char fd1string[] = "This file should get closed";
+static const char fd2string[] = "This file should stay opened";
+
+
+/* We have a preparation function. */
+void
+do_prepare (int argc, char *argv[])
+{
+ char name_len;
+
+ name_len = strlen (test_dir);
+ name1 = malloc (name_len + sizeof ("/execXXXXXX"));
+ mempcpy (mempcpy (name1, test_dir, name_len),
+ "/execXXXXXX", sizeof ("/execXXXXXX"));
+ add_temp_file (name1);
+
+ name2 = malloc (name_len + sizeof ("/execXXXXXX"));
+ mempcpy (mempcpy (name2, test_dir, name_len),
+ "/execXXXXXX", sizeof ("/execXXXXXX"));
+ add_temp_file (name2);
+}
+
+
+static int
+handle_restart (const char *fd1s, const char *fd2s, const char *name)
+{
+ char buf[100];
+ int fd1;
+ int fd2;
+
+ /* First get the descriptors. */
+ fd1 = atol (fd1s);
+ fd2 = atol (fd2s);
+
+ /* Sanity check. */
+ if (fd1 == fd2)
+ error (EXIT_FAILURE, 0, "value of fd1 and fd2 is the same");
+
+ /* First the easy part: read from the file descriptor which is
+ supposed to be open. */
+ if (lseek (fd2, 0, SEEK_CUR) != strlen (fd2string))
+ error (EXIT_FAILURE, errno, "file 2 not in right position");
+ if (lseek (fd2, 0, SEEK_SET) != 0)
+ error (EXIT_FAILURE, 0, "cannot reset position in file 2");
+ if (read (fd2, buf, sizeof buf) != strlen (fd2string))
+ error (EXIT_FAILURE, 0, "cannot read file 2");
+ if (memcmp (fd2string, buf, strlen (fd2string)) != 0)
+ error (EXIT_FAILURE, 0, "file 2 does not match");
+
+ /* No try to read the first file. First make sure it is not opened. */
+ if (lseek (fd1, 0, SEEK_CUR) != (off_t) -1 || errno != EBADF)
+ error (EXIT_FAILURE, 0, "file 1 (%d) is not closed", fd1);
+
+ /* Now open the file and read it. */
+ fd1 = open (name, O_RDONLY);
+ if (fd1 == -1)
+ error (EXIT_FAILURE, errno,
+ "cannot open first file \"%s\" for verification", name);
+
+ if (read (fd1, buf, sizeof buf) != strlen (fd1string))
+ error (EXIT_FAILURE, errno, "cannot read file 1");
+ if (memcmp (fd1string, buf, strlen (fd1string)) != 0)
+ error (EXIT_FAILURE, 0, "file 1 does not match");
+
+ return 0;
+}
+
+
+int
+do_test (int argc, char *argv[])
+{
+ pid_t pid;
+ int fd1;
+ int fd2;
+ int flags;
+ int status;
+
+ /* We must have
+ - four parameters left of called initially
+ + path for ld.so
+ + "--library-path"
+ + the library path
+ + the application name
+ - three parameters left if called through re-execution
+ + file descriptor number which is supposed to be closed
+ + the open file descriptor
+ + the name of the closed desriptor
+ */
+
+ if (restart)
+ {
+ if (argc != 4)
+ error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc);
+
+ return handle_restart (argv[1], argv[2], argv[3]);
+ }
+
+ if (argc != 5)
+ error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc);
+
+ /* Prepare the test. We are creating two files: one which file descriptor
+ will be marked with FD_CLOEXEC, another which is not. */
+
+ /* Open our test files. */
+ fd1 = mkstemp (name1);
+ if (fd1 == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name1);
+ fd2 = mkstemp (name2);
+ if (fd2 == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name2);
+
+ /* Set the bit. */
+ flags = fcntl (fd1, F_GETFD, 0);
+ if (flags < 0)
+ error (EXIT_FAILURE, errno, "cannot get flags");
+ flags |= FD_CLOEXEC;
+ if (fcntl (fd1, F_SETFD, flags) < 0)
+ error (EXIT_FAILURE, errno, "cannot set flags");
+
+ /* Write something in the files. */
+ if (write (fd1, fd1string, strlen (fd1string)) != strlen (fd1string))
+ error (EXIT_FAILURE, errno, "cannot write to first file");
+ if (write (fd2, fd2string, strlen (fd2string)) != strlen (fd2string))
+ error (EXIT_FAILURE, errno, "cannot write to second file");
+
+ /* We want to test the `exec' function. To do this we restart the program
+ with an additional parameter. But first create another process. */
+ pid = fork ();
+ if (pid == 0)
+ {
+ char fd1name[18];
+ char fd2name[18];
+
+ snprintf (fd1name, sizeof fd1name, "%d", fd1);
+ snprintf (fd2name, sizeof fd2name, "%d", fd2);
+
+ /* This is the child. Construct the command line. */
+ execl (argv[1], argv[1], argv[2], argv[3], argv[4], "--direct",
+ "--restart", fd1name, fd2name, name1, NULL);
+
+ error (EXIT_FAILURE, errno, "cannot exec");
+ }
+ else if (pid == (pid_t) -1)
+ error (EXIT_FAILURE, errno, "cannot fork");
+
+ /* Wait for the child. */
+ if (waitpid (pid, &status, 0) != pid)
+ error (EXIT_FAILURE, errno, "wrong child");
+
+ if (WTERMSIG (status) != 0)
+ error (EXIT_FAILURE, 0, "Child terminated incorrectly");
+ status = WEXITSTATUS (status);
+
+ /* Remove the test files. */
+ unlink (name1);
+ unlink (name2);
+
+ return status;
+}
diff --git a/libc/posix/tst-execl1.c b/libc/posix/tst-execl1.c
new file mode 100644
index 000000000..1cfa36df1
--- /dev/null
+++ b/libc/posix/tst-execl1.c
@@ -0,0 +1,22 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ static const char prog[] = "does-not-exist";
+ errno = 0;
+ execl (prog, prog, NULL);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execl2.c b/libc/posix/tst-execl2.c
new file mode 100644
index 000000000..5b74959ef
--- /dev/null
+++ b/libc/posix/tst-execl2.c
@@ -0,0 +1,58 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ errno = 0;
+ execl (copy, copy, NULL);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execle1.c b/libc/posix/tst-execle1.c
new file mode 100644
index 000000000..84470703f
--- /dev/null
+++ b/libc/posix/tst-execle1.c
@@ -0,0 +1,23 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ static const char prog[] = "does-not-exist";
+ const char *env [] = {"FOO=BAR", NULL};
+ errno = 0;
+ execle (prog, prog, NULL, env);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execle2.c b/libc/posix/tst-execle2.c
new file mode 100644
index 000000000..0430b7b57
--- /dev/null
+++ b/libc/posix/tst-execle2.c
@@ -0,0 +1,59 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ const char *env[] = {"FOO=BAR", NULL};
+ errno = 0;
+ execle (copy, copy, NULL, env);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execlp1.c b/libc/posix/tst-execlp1.c
new file mode 100644
index 000000000..1be4dbcb1
--- /dev/null
+++ b/libc/posix/tst-execlp1.c
@@ -0,0 +1,34 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ char *cwd = get_current_dir_name ();
+ if (cwd == NULL)
+ {
+ puts ("get_current_dir_name failed");
+ return 1;
+ }
+
+ /* Make sure we do not find a binary with the name we are going to
+ use. */
+ setenv ("PATH", cwd, 1);
+
+ static const char prog[] = "does-not-exist";
+ errno = 0;
+ execlp (prog, prog, NULL);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execlp2.c b/libc/posix/tst-execlp2.c
new file mode 100644
index 000000000..81a723dda
--- /dev/null
+++ b/libc/posix/tst-execlp2.c
@@ -0,0 +1,82 @@
+#include <errno.h>
+#include <libgen.h>
+#undef basename
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ /* Make sure we do not find a binary with the name we are going to
+ use. */
+ char *bindir = strdupa (copy);
+ bindir = canonicalize_file_name (dirname (bindir));
+ if (bindir == NULL)
+ {
+ puts ("canonicalize_file_name failed");
+ return 1;
+ }
+ char *path;
+ asprintf (&path, "%s:../libio:../elf", bindir);
+ if (path == NULL)
+ {
+ puts ("asprintf failed");
+ return 1;
+ }
+
+ setenv ("PATH", path, 1);
+
+ char *prog = basename (copy);
+ errno = 0;
+ execlp (prog, prog, NULL);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execv1.c b/libc/posix/tst-execv1.c
new file mode 100644
index 000000000..57ed1add6
--- /dev/null
+++ b/libc/posix/tst-execv1.c
@@ -0,0 +1,22 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ char *argv[] = { (char *) "does-not-exist", NULL };
+ errno = 0;
+ execv (argv[0], argv);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execv2.c b/libc/posix/tst-execv2.c
new file mode 100644
index 000000000..a5168a269
--- /dev/null
+++ b/libc/posix/tst-execv2.c
@@ -0,0 +1,60 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ char *argv[] = { copy, NULL };
+
+ errno = 0;
+ execv (copy, argv);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execve1.c b/libc/posix/tst-execve1.c
new file mode 100644
index 000000000..356610f63
--- /dev/null
+++ b/libc/posix/tst-execve1.c
@@ -0,0 +1,23 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ char *argv[] = { (char *) "does-not-exist", NULL };
+ char *envp[] = { (char *) "FOO=BAR", NULL };
+ errno = 0;
+ execve (argv[0], argv, envp);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execve2.c b/libc/posix/tst-execve2.c
new file mode 100644
index 000000000..1a804e94f
--- /dev/null
+++ b/libc/posix/tst-execve2.c
@@ -0,0 +1,61 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ char *argv[] = { copy, NULL };
+ char *envp[] = { (char *) "FOO=BAR", NULL };
+
+ errno = 0;
+ execve (copy, argv, envp);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execvp1.c b/libc/posix/tst-execvp1.c
new file mode 100644
index 000000000..ecc673d12
--- /dev/null
+++ b/libc/posix/tst-execvp1.c
@@ -0,0 +1,34 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ char *cwd = get_current_dir_name ();
+ if (cwd == NULL)
+ {
+ puts ("get_current_dir_name failed");
+ return 1;
+ }
+
+ /* Make sure we do not find a binary with the name we are going to
+ use. */
+ setenv ("PATH", cwd, 1);
+
+ char *argv[] = { (char *) "does-not-exist", NULL };
+ errno = 0;
+ execvp (argv[0], argv);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno = %d (%m), expected ENOENT\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-execvp2.c b/libc/posix/tst-execvp2.c
new file mode 100644
index 000000000..7e0f5d882
--- /dev/null
+++ b/libc/posix/tst-execvp2.c
@@ -0,0 +1,82 @@
+#include <errno.h>
+#include <libgen.h>
+#undef basename
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void prepare (int argc, char *argv[]);
+static int do_test (void);
+#define PREPARE(argc, argv) prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
+static char *copy;
+
+static void
+prepare (int argc, char *argv[])
+{
+ char *buf;
+ int off;
+ asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]);
+ if (buf == NULL)
+ {
+ puts ("asprintf failed");
+ exit (1);
+ }
+ if (system (buf) != 0)
+ {
+ puts ("system failed");
+ exit (1);
+ }
+
+ /* Make it not executable. */
+ copy = buf + off;
+ if (chmod (copy, 0666) != 0)
+ {
+ puts ("chmod failed");
+ exit (1);
+ }
+
+ add_temp_file (copy);
+}
+
+
+static int
+do_test (void)
+{
+ /* Make sure we do not find a binary with the name we are going to
+ use. */
+ char *bindir = strdupa (copy);
+ bindir = canonicalize_file_name (dirname (bindir));
+ if (bindir == NULL)
+ {
+ puts ("canonicalize_file_name failed");
+ return 1;
+ }
+ char *path;
+ asprintf (&path, "%s:../libio:../elf", bindir);
+ if (path == NULL)
+ {
+ puts ("asprintf failed");
+ return 1;
+ }
+
+ setenv ("PATH", path, 1);
+
+ char *argv[] = { basename (copy), NULL };
+ errno = 0;
+ execvp (argv[0], argv);
+
+ if (errno != EACCES)
+ {
+ printf ("errno = %d (%m), expected EACCES\n", errno);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libc/posix/tst-execvp3.c b/libc/posix/tst-execvp3.c
new file mode 100644
index 000000000..5ebc87952
--- /dev/null
+++ b/libc/posix/tst-execvp3.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static void do_prepare (void);
+#define PREPARE(argc, argv) do_prepare ()
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+
+static char *fname;
+
+static void
+do_prepare (void)
+{
+ int fd = create_temp_file ("testscript", &fname);
+ dprintf (fd, "echo foo\n");
+ fchmod (fd, 0700);
+ close (fd);
+}
+
+
+static int
+do_test (void)
+{
+ if (setenv ("PATH", test_dir, 1) != 0)
+ {
+ puts ("setenv failed");
+ return 1;
+ }
+
+ char *argv[] = { fname, NULL };
+ execvp (basename (fname), argv);
+
+ /* If we come here, the execvp call failed. */
+ return 1;
+}
diff --git a/libc/posix/tst-execvp4.c b/libc/posix/tst-execvp4.c
new file mode 100644
index 000000000..531fab227
--- /dev/null
+++ b/libc/posix/tst-execvp4.c
@@ -0,0 +1,35 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int
+do_test (void)
+{
+ char buf[40] = "/usr/bin/does-not-exist";
+ size_t stemlen = strlen (buf);
+ struct stat64 st;
+ int cnt = 0;
+ while (stat64 (buf, &st) != -1 || errno != ENOENT
+ || stat64 (buf + 4, &st) != -1 || errno != ENOENT)
+ {
+ if (cnt++ == 100)
+ {
+ puts ("cannot find a unique file name");
+ return 0;
+ }
+
+ strcpy (buf + stemlen, ".XXXXXX");
+ mktemp (buf);
+ }
+
+ unsetenv ("PATH");
+ char *argv[] = { buf + 9, NULL };
+ execvp (argv[0], argv);
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-fnmatch.c b/libc/posix/tst-fnmatch.c
new file mode 100644
index 000000000..25471f8e4
--- /dev/null
+++ b/libc/posix/tst-fnmatch.c
@@ -0,0 +1,388 @@
+/* Tests for fnmatch function.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <fnmatch.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+
+static char *next_input (char **line, int first, int last);
+static int convert_flags (const char *str);
+static char *flag_output (int flags);
+static char *escape (const char *str, size_t *reslenp, char **resbuf);
+
+
+int
+main (void)
+{
+ char *linebuf = NULL;
+ size_t linebuflen = 0;
+ int ntests = 0;
+ int nfailed = 0;
+ char *escinput = NULL;
+ size_t escinputlen = 0;
+ char *escpattern = NULL;
+ size_t escpatternlen = 0;
+ int nr = 0;
+
+ /* Read lines from stdin with the following format:
+
+ locale input-string match-string flags result
+
+ where `result' is either 0 or 1. If the first character of a
+ string is '"' we read until the next '"' and handled escaped '"'. */
+ while (! feof (stdin))
+ {
+ ssize_t n = getline (&linebuf, &linebuflen, stdin);
+ char *cp;
+ const char *locale;
+ const char *input;
+ const char *pattern;
+ const char *result_str;
+ int result;
+ const char *flags;
+ int flags_val;
+ int fnmres;
+ char numbuf[24];
+
+ if (n == -1)
+ break;
+
+ if (n == 0)
+ /* Maybe an empty line. */
+ continue;
+
+ /* Skip over all leading white spaces. */
+ cp = linebuf;
+
+ locale = next_input (&cp, 1, 0);
+ if (locale == NULL)
+ continue;
+
+ input = next_input (&cp, 0, 0);
+ if (input == NULL)
+ continue;
+
+ pattern = next_input (&cp, 0, 0);
+ if (pattern == NULL)
+ continue;
+
+ result_str = next_input (&cp, 0, 0);
+ if (result_str == NULL)
+ continue;
+
+ if (strcmp (result_str, "0") == 0)
+ result = 0;
+ else if (strcasecmp (result_str, "NOMATCH") == 0)
+ result = FNM_NOMATCH;
+ else
+ {
+ char *endp;
+ result = strtol (result_str, &endp, 0);
+ if (*endp != '\0')
+ continue;
+ }
+
+ flags = next_input (&cp, 0, 1);
+ if (flags == NULL)
+ /* We allow the flags missing. */
+ flags = "";
+
+ /* Convert the text describing the flags in a numeric value. */
+ flags_val = convert_flags (flags);
+ if (flags_val == -1)
+ /* Something went wrong. */
+ continue;
+
+ /* Now run the actual test. */
+ ++ntests;
+
+ if (setlocale (LC_COLLATE, locale) == NULL
+ || setlocale (LC_CTYPE, locale) == NULL)
+ {
+ puts ("*** Cannot set locale");
+ ++nfailed;
+ continue;
+ }
+
+ fnmres = fnmatch (pattern, input, flags_val);
+
+ printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
+ ++nr,
+ escape (pattern, &escpatternlen, &escpattern),
+ escape (input, &escinputlen, &escinput),
+ flag_output (flags_val),
+ (fnmres == 0
+ ? "0" : (fnmres == FNM_NOMATCH
+ ? "FNM_NOMATCH"
+ : (sprintf (numbuf, "%d", fnmres), numbuf))),
+ (fnmres != 0) != (result != 0) ? ' ' : '\n');
+
+ if ((fnmres != 0) != (result != 0))
+ {
+ printf ("(FAIL, expected %s) ***\n",
+ result == 0
+ ? "0" : (result == FNM_NOMATCH
+ ? "FNM_NOMATCH"
+ : (sprintf (numbuf, "%d", result), numbuf)));
+ ++nfailed;
+ }
+ }
+
+ printf ("=====================\n%3d tests, %3d failed\n", ntests, nfailed);
+
+ free (escpattern);
+ free (escinput);
+ free (linebuf);
+
+ return nfailed != 0;
+}
+
+
+static char *
+next_input (char **line, int first, int last)
+{
+ char *cp = *line;
+ char *result;
+
+ while (*cp == ' ' || *cp == '\t')
+ ++cp;
+
+ /* We allow comment lines starting with '#'. */
+ if (first && *cp == '#')
+ return NULL;
+
+ if (*cp == '"')
+ {
+ char *wp;
+
+ result = ++cp;
+ wp = cp;
+
+ while (*cp != '"' && *cp != '\0' && *cp != '\n')
+ if (*cp == '\\')
+ {
+ if (cp[1] == '\n' || cp[1] == '\0')
+ return NULL;
+
+ ++cp;
+ if (*cp == 't')
+ *wp++ = '\t';
+ else if (*cp == 'n')
+ *wp++ = '\n';
+ else
+ *wp++ = *cp;
+
+ ++cp;
+ }
+ else
+ *wp++ = *cp++;
+
+ if (*cp != '"')
+ return NULL;
+
+ if (wp != cp)
+ *wp = '\0';
+ }
+ else
+ {
+ result = cp;
+ while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
+ ++cp;
+
+ if (cp == result && ! last)
+ /* Premature end of line. */
+ return NULL;
+ }
+
+ /* Terminate and skip over the next white spaces. */
+ *cp++ = '\0';
+
+ *line = cp;
+ return result;
+}
+
+
+static int
+convert_flags (const char *str)
+{
+ int result = 0;
+
+ while (*str != '\0')
+ {
+ int len;
+
+ if (strncasecmp (str, "PATHNAME", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_PATHNAME;
+ len = 8;
+ }
+ else if (strncasecmp (str, "NOESCAPE", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_NOESCAPE;
+ len = 8;
+ }
+ else if (strncasecmp (str, "PERIOD", 6) == 0
+ && (str[6] == '|' || str[6] == '\0'))
+ {
+ result |= FNM_PERIOD;
+ len = 6;
+ }
+ else if (strncasecmp (str, "LEADING_DIR", 11) == 0
+ && (str[11] == '|' || str[11] == '\0'))
+ {
+ result |= FNM_LEADING_DIR;
+ len = 11;
+ }
+ else if (strncasecmp (str, "CASEFOLD", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_CASEFOLD;
+ len = 8;
+ }
+ else if (strncasecmp (str, "EXTMATCH", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_EXTMATCH;
+ len = 8;
+ }
+ else
+ return -1;
+
+ str += len;
+ if (*str != '\0')
+ ++str;
+ }
+
+ return result;
+}
+
+
+static char *
+flag_output (int flags)
+{
+ static char buf[100];
+ int first = 1;
+ char *cp = buf;
+
+ if (flags & FNM_PATHNAME)
+ {
+ cp = stpcpy (cp, "FNM_PATHNAME");
+ first = 0;
+ }
+ if (flags & FNM_NOESCAPE)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_NOESCAPE");
+ first = 0;
+ }
+ if (flags & FNM_PERIOD)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_PERIOD");
+ first = 0;
+ }
+ if (flags & FNM_LEADING_DIR)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_LEADING_DIR");
+ first = 0;
+ }
+ if (flags & FNM_CASEFOLD)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_CASEFOLD");
+ first = 0;
+ }
+ if (flags & FNM_EXTMATCH)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_EXTMATCH");
+ first = 0;
+ }
+ if (cp == buf)
+ *cp++ = '0';
+ *cp = '\0';
+
+ return buf;
+}
+
+
+static char *
+escape (const char *str, size_t *reslenp, char **resbufp)
+{
+ size_t reslen = *reslenp;
+ char *resbuf = *resbufp;
+ size_t len = strlen (str);
+ char *wp;
+
+ if (2 * len + 1 > reslen)
+ {
+ resbuf = (char *) realloc (resbuf, 2 * len + 1);
+ if (resbuf == NULL)
+ error (EXIT_FAILURE, errno, "while allocating buffer for printing");
+ *reslenp = 2 * len + 1;
+ *resbufp = resbuf;
+ }
+
+ wp = resbuf;
+ while (*str != '\0')
+ if (*str == '\t')
+ {
+ *wp++ = '\\';
+ *wp++ = 't';
+ ++str;
+ }
+ else if (*str == '\n')
+ {
+ *wp++ = '\\';
+ *wp++ = 'n';
+ ++str;
+ }
+ else if (*str == '"')
+ {
+ *wp++ = '\\';
+ *wp++ = '"';
+ ++str;
+ }
+ else if (*str == '\\')
+ {
+ *wp++ = '\\';
+ *wp++ = '\\';
+ ++str;
+ }
+ else
+ *wp++ = *str++;
+
+ *wp = '\0';
+
+ return resbuf;
+}
diff --git a/libc/posix/tst-fnmatch.input b/libc/posix/tst-fnmatch.input
new file mode 100644
index 000000000..9061d1994
--- /dev/null
+++ b/libc/posix/tst-fnmatch.input
@@ -0,0 +1,755 @@
+# Tests for fnmatch.
+# Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributes by Ulrich Drepper <drepper@redhat.com>.
+#
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+
+# Derived from the IEEE 2003.2 text. The standard only contains some
+# wording describing the situations to be tested. It does not specify
+# any specific tests. I.e., the tests below are in no case sufficient.
+# They are hopefully necessary, though.
+
+# B.6 004(C)
+C "!#%+,-./01234567889" "!#%+,-./01234567889" 0
+C ":;=@ABCDEFGHIJKLMNO" ":;=@ABCDEFGHIJKLMNO" 0
+C "PQRSTUVWXYZ]abcdefg" "PQRSTUVWXYZ]abcdefg" 0
+C "hijklmnopqrstuvwxyz" "hijklmnopqrstuvwxyz" 0
+C "^_{}~" "^_{}~" 0
+
+# B.6 005(C)
+C "\"$&'()" "\\\"\\$\\&\\'\\(\\)" 0
+C "*?[\\`|" "\\*\\?\\[\\\\\\`\\|" 0
+C "<>" "\\<\\>" 0
+
+# B.6 006(C)
+C "?*[" "[?*[][?*[][?*[]" 0
+C "a/b" "?/b" 0
+
+# B.6 007(C)
+C "a/b" "a?b" 0
+C "a/b" "a/?" 0
+C "aa/b" "?/b" NOMATCH
+C "aa/b" "a?b" NOMATCH
+C "a/bb" "a/?" NOMATCH
+
+# B.6 009(C)
+C "abc" "[abc]" NOMATCH
+C "x" "[abc]" NOMATCH
+C "a" "[abc]" 0
+C "[" "[[abc]" 0
+C "a" "[][abc]" 0
+C "a]" "[]a]]" 0
+
+# B.6 010(C)
+C "xyz" "[!abc]" NOMATCH
+C "x" "[!abc]" 0
+C "a" "[!abc]" NOMATCH
+
+# B.6 011(C)
+C "]" "[][abc]" 0
+C "abc]" "[][abc]" NOMATCH
+C "[]abc" "[][]abc" NOMATCH
+C "]" "[!]]" NOMATCH
+C "aa]" "[!]a]" NOMATCH
+C "]" "[!a]" 0
+C "]]" "[!a]]" 0
+
+# B.6 012(C)
+C "a" "[[.a.]]" 0
+C "-" "[[.-.]]" 0
+C "-" "[[.-.][.].]]" 0
+C "-" "[[.].][.-.]]" 0
+C "-" "[[.-.][=u=]]" 0
+C "-" "[[.-.][:alpha:]]" 0
+C "a" "[![.a.]]" NOMATCH
+
+# B.6 013(C)
+C "a" "[[.b.]]" NOMATCH
+C "a" "[[.b.][.c.]]" NOMATCH
+C "a" "[[.b.][=b=]]" NOMATCH
+
+
+# B.6 015(C)
+C "a" "[[=a=]]" 0
+C "b" "[[=a=]b]" 0
+C "b" "[[=a=][=b=]]" 0
+C "a" "[[=a=][=b=]]" 0
+C "a" "[[=a=][.b.]]" 0
+C "a" "[[=a=][:digit:]]" 0
+
+# B.6 016(C)
+C "=" "[[=a=]b]" NOMATCH
+C "]" "[[=a=]b]" NOMATCH
+C "a" "[[=b=][=c=]]" NOMATCH
+C "a" "[[=b=][.].]]" NOMATCH
+C "a" "[[=b=][:digit:]]" NOMATCH
+
+# B.6 017(C)
+C "a" "[[:alnum:]]" 0
+C "a" "[![:alnum:]]" NOMATCH
+C "-" "[[:alnum:]]" NOMATCH
+C "a]a" "[[:alnum:]]a" NOMATCH
+C "-" "[[:alnum:]-]" 0
+C "aa" "[[:alnum:]]a" 0
+C "-" "[![:alnum:]]" 0
+C "]" "[!][:alnum:]]" NOMATCH
+C "[" "[![:alnum:][]" NOMATCH
+C "a" "[[:alnum:]]" 0
+C "b" "[[:alnum:]]" 0
+C "c" "[[:alnum:]]" 0
+C "d" "[[:alnum:]]" 0
+C "e" "[[:alnum:]]" 0
+C "f" "[[:alnum:]]" 0
+C "g" "[[:alnum:]]" 0
+C "h" "[[:alnum:]]" 0
+C "i" "[[:alnum:]]" 0
+C "j" "[[:alnum:]]" 0
+C "k" "[[:alnum:]]" 0
+C "l" "[[:alnum:]]" 0
+C "m" "[[:alnum:]]" 0
+C "n" "[[:alnum:]]" 0
+C "o" "[[:alnum:]]" 0
+C "p" "[[:alnum:]]" 0
+C "q" "[[:alnum:]]" 0
+C "r" "[[:alnum:]]" 0
+C "s" "[[:alnum:]]" 0
+C "t" "[[:alnum:]]" 0
+C "u" "[[:alnum:]]" 0
+C "v" "[[:alnum:]]" 0
+C "w" "[[:alnum:]]" 0
+C "x" "[[:alnum:]]" 0
+C "y" "[[:alnum:]]" 0
+C "z" "[[:alnum:]]" 0
+C "A" "[[:alnum:]]" 0
+C "B" "[[:alnum:]]" 0
+C "C" "[[:alnum:]]" 0
+C "D" "[[:alnum:]]" 0
+C "E" "[[:alnum:]]" 0
+C "F" "[[:alnum:]]" 0
+C "G" "[[:alnum:]]" 0
+C "H" "[[:alnum:]]" 0
+C "I" "[[:alnum:]]" 0
+C "J" "[[:alnum:]]" 0
+C "K" "[[:alnum:]]" 0
+C "L" "[[:alnum:]]" 0
+C "M" "[[:alnum:]]" 0
+C "N" "[[:alnum:]]" 0
+C "O" "[[:alnum:]]" 0
+C "P" "[[:alnum:]]" 0
+C "Q" "[[:alnum:]]" 0
+C "R" "[[:alnum:]]" 0
+C "S" "[[:alnum:]]" 0
+C "T" "[[:alnum:]]" 0
+C "U" "[[:alnum:]]" 0
+C "V" "[[:alnum:]]" 0
+C "W" "[[:alnum:]]" 0
+C "X" "[[:alnum:]]" 0
+C "Y" "[[:alnum:]]" 0
+C "Z" "[[:alnum:]]" 0
+C "0" "[[:alnum:]]" 0
+C "1" "[[:alnum:]]" 0
+C "2" "[[:alnum:]]" 0
+C "3" "[[:alnum:]]" 0
+C "4" "[[:alnum:]]" 0
+C "5" "[[:alnum:]]" 0
+C "6" "[[:alnum:]]" 0
+C "7" "[[:alnum:]]" 0
+C "8" "[[:alnum:]]" 0
+C "9" "[[:alnum:]]" 0
+C "!" "[[:alnum:]]" NOMATCH
+C "#" "[[:alnum:]]" NOMATCH
+C "%" "[[:alnum:]]" NOMATCH
+C "+" "[[:alnum:]]" NOMATCH
+C "," "[[:alnum:]]" NOMATCH
+C "-" "[[:alnum:]]" NOMATCH
+C "." "[[:alnum:]]" NOMATCH
+C "/" "[[:alnum:]]" NOMATCH
+C ":" "[[:alnum:]]" NOMATCH
+C ";" "[[:alnum:]]" NOMATCH
+C "=" "[[:alnum:]]" NOMATCH
+C "@" "[[:alnum:]]" NOMATCH
+C "[" "[[:alnum:]]" NOMATCH
+C "\\" "[[:alnum:]]" NOMATCH
+C "]" "[[:alnum:]]" NOMATCH
+C "^" "[[:alnum:]]" NOMATCH
+C "_" "[[:alnum:]]" NOMATCH
+C "{" "[[:alnum:]]" NOMATCH
+C "}" "[[:alnum:]]" NOMATCH
+C "~" "[[:alnum:]]" NOMATCH
+C "\"" "[[:alnum:]]" NOMATCH
+C "$" "[[:alnum:]]" NOMATCH
+C "&" "[[:alnum:]]" NOMATCH
+C "'" "[[:alnum:]]" NOMATCH
+C "(" "[[:alnum:]]" NOMATCH
+C ")" "[[:alnum:]]" NOMATCH
+C "*" "[[:alnum:]]" NOMATCH
+C "?" "[[:alnum:]]" NOMATCH
+C "`" "[[:alnum:]]" NOMATCH
+C "|" "[[:alnum:]]" NOMATCH
+C "<" "[[:alnum:]]" NOMATCH
+C ">" "[[:alnum:]]" NOMATCH
+C "\t" "[[:cntrl:]]" 0
+C "t" "[[:cntrl:]]" NOMATCH
+C "t" "[[:lower:]]" 0
+C "\t" "[[:lower:]]" NOMATCH
+C "T" "[[:lower:]]" NOMATCH
+C "\t" "[[:space:]]" 0
+C "t" "[[:space:]]" NOMATCH
+C "t" "[[:alpha:]]" 0
+C "\t" "[[:alpha:]]" NOMATCH
+C "0" "[[:digit:]]" 0
+C "\t" "[[:digit:]]" NOMATCH
+C "t" "[[:digit:]]" NOMATCH
+C "\t" "[[:print:]]" NOMATCH
+C "t" "[[:print:]]" 0
+C "T" "[[:upper:]]" 0
+C "\t" "[[:upper:]]" NOMATCH
+C "t" "[[:upper:]]" NOMATCH
+C "\t" "[[:blank:]]" 0
+C "t" "[[:blank:]]" NOMATCH
+C "\t" "[[:graph:]]" NOMATCH
+C "t" "[[:graph:]]" 0
+C "." "[[:punct:]]" 0
+C "t" "[[:punct:]]" NOMATCH
+C "\t" "[[:punct:]]" NOMATCH
+C "0" "[[:xdigit:]]" 0
+C "\t" "[[:xdigit:]]" NOMATCH
+C "a" "[[:xdigit:]]" 0
+C "A" "[[:xdigit:]]" 0
+C "t" "[[:xdigit:]]" NOMATCH
+C "a" "[[alpha]]" NOMATCH
+C "a" "[[alpha:]]" NOMATCH
+C "a]" "[[alpha]]" 0
+C "a]" "[[alpha:]]" 0
+C "a" "[[:alpha:][.b.]]" 0
+C "a" "[[:alpha:][=b=]]" 0
+C "a" "[[:alpha:][:digit:]]" 0
+C "a" "[[:digit:][:alpha:]]" 0
+
+# B.6 018(C)
+C "a" "[a-c]" 0
+C "b" "[a-c]" 0
+C "c" "[a-c]" 0
+C "a" "[b-c]" NOMATCH
+C "d" "[b-c]" NOMATCH
+C "B" "[a-c]" NOMATCH
+C "b" "[A-C]" NOMATCH
+C "" "[a-c]" NOMATCH
+C "as" "[a-ca-z]" NOMATCH
+C "a" "[[.a.]-c]" 0
+C "a" "[a-[.c.]]" 0
+C "a" "[[.a.]-[.c.]]" 0
+C "b" "[[.a.]-c]" 0
+C "b" "[a-[.c.]]" 0
+C "b" "[[.a.]-[.c.]]" 0
+C "c" "[[.a.]-c]" 0
+C "c" "[a-[.c.]]" 0
+C "c" "[[.a.]-[.c.]]" 0
+C "d" "[[.a.]-c]" NOMATCH
+C "d" "[a-[.c.]]" NOMATCH
+C "d" "[[.a.]-[.c.]]" NOMATCH
+
+# B.6 019(C)
+C "a" "[c-a]" NOMATCH
+C "a" "[[.c.]-a]" NOMATCH
+C "a" "[c-[.a.]]" NOMATCH
+C "a" "[[.c.]-[.a.]]" NOMATCH
+C "c" "[c-a]" NOMATCH
+C "c" "[[.c.]-a]" NOMATCH
+C "c" "[c-[.a.]]" NOMATCH
+C "c" "[[.c.]-[.a.]]" NOMATCH
+
+# B.6 020(C)
+C "a" "[a-c0-9]" 0
+C "d" "[a-c0-9]" NOMATCH
+C "B" "[a-c0-9]" NOMATCH
+
+# B.6 021(C)
+C "-" "[-a]" 0
+C "a" "[-b]" NOMATCH
+C "-" "[!-a]" NOMATCH
+C "a" "[!-b]" 0
+C "-" "[a-c-0-9]" 0
+C "b" "[a-c-0-9]" 0
+C "a:" "a[0-9-a]" NOMATCH
+C "a:" "a[09-a]" 0
+
+# B.6 024(C)
+C "" "*" 0
+C "asd/sdf" "*" 0
+
+# B.6 025(C)
+C "as" "[a-c][a-z]" 0
+C "as" "??" 0
+
+# B.6 026(C)
+C "asd/sdf" "as*df" 0
+C "asd/sdf" "as*" 0
+C "asd/sdf" "*df" 0
+C "asd/sdf" "as*dg" NOMATCH
+C "asdf" "as*df" 0
+C "asdf" "as*df?" NOMATCH
+C "asdf" "as*??" 0
+C "asdf" "a*???" 0
+C "asdf" "*????" 0
+C "asdf" "????*" 0
+C "asdf" "??*?" 0
+
+# B.6 027(C)
+C "/" "/" 0
+C "/" "/*" 0
+C "/" "*/" 0
+C "/" "/?" NOMATCH
+C "/" "?/" NOMATCH
+C "/" "?" 0
+C "." "?" 0
+C "/." "??" 0
+C "/" "[!a-c]" 0
+C "." "[!a-c]" 0
+
+# B.6 029(C)
+C "/" "/" 0 PATHNAME
+C "//" "//" 0 PATHNAME
+C "/.a" "/*" 0 PATHNAME
+C "/.a" "/?a" 0 PATHNAME
+C "/.a" "/[!a-z]a" 0 PATHNAME
+C "/.a/.b" "/*/?b" 0 PATHNAME
+
+# B.6 030(C)
+C "/" "?" NOMATCH PATHNAME
+C "/" "*" NOMATCH PATHNAME
+C "a/b" "a?b" NOMATCH PATHNAME
+C "/.a/.b" "/*b" NOMATCH PATHNAME
+
+# B.6 031(C)
+C "/$" "\\/\\$" 0
+C "/[" "\\/\\[" 0
+C "/[" "\\/[" NOMATCH
+
+# B.6 032(C)
+C "/$" "\\/\\$" NOMATCH NOESCAPE
+C "/\\$" "\\/\\$" NOMATCH NOESCAPE
+C "\\/\\$" "\\/\\$" 0 NOESCAPE
+
+# B.6 033(C)
+C ".asd" ".*" 0 PERIOD
+C "/.asd" "*" 0 PERIOD
+C "/as/.df" "*/?*f" 0 PERIOD
+C "..asd" ".[!a-z]*" 0 PERIOD
+
+# B.6 034(C)
+C ".asd" "*" NOMATCH PERIOD
+C ".asd" "?asd" NOMATCH PERIOD
+C ".asd" "[!a-z]*" NOMATCH PERIOD
+
+# B.6 035(C)
+C "/." "/." 0 PATHNAME|PERIOD
+C "/.a./.b." "/.*/.*" 0 PATHNAME|PERIOD
+C "/.a./.b." "/.??/.??" 0 PATHNAME|PERIOD
+
+# B.6 036(C)
+C "/." "*" NOMATCH PATHNAME|PERIOD
+C "/." "/*" NOMATCH PATHNAME|PERIOD
+C "/." "/?" NOMATCH PATHNAME|PERIOD
+C "/." "/[!a-z]" NOMATCH PATHNAME|PERIOD
+C "/a./.b." "/*/*" NOMATCH PATHNAME|PERIOD
+C "/a./.b." "/??/???" NOMATCH PATHNAME|PERIOD
+
+# Some home-grown tests.
+C "foobar" "foo*[abc]z" NOMATCH
+C "foobaz" "foo*[abc][xyz]" 0
+C "foobaz" "foo?*[abc][xyz]" 0
+C "foobaz" "foo?*[abc][x/yz]" 0
+C "foobaz" "foo?*[abc]/[xyz]" NOMATCH PATHNAME
+C "a" "a/" NOMATCH PATHNAME
+C "a/" "a" NOMATCH PATHNAME
+C "//a" "/a" NOMATCH PATHNAME
+C "/a" "//a" NOMATCH PATHNAME
+C "az" "[a-]z" 0
+C "bz" "[ab-]z" 0
+C "cz" "[ab-]z" NOMATCH
+C "-z" "[ab-]z" 0
+C "az" "[-a]z" 0
+C "bz" "[-ab]z" 0
+C "cz" "[-ab]z" NOMATCH
+C "-z" "[-ab]z" 0
+C "\\" "[\\\\-a]" 0
+C "_" "[\\\\-a]" 0
+C "a" "[\\\\-a]" 0
+C "-" "[\\\\-a]" NOMATCH
+C "\\" "[\\]-a]" NOMATCH
+C "_" "[\\]-a]" 0
+C "a" "[\\]-a]" 0
+C "]" "[\\]-a]" 0
+C "-" "[\\]-a]" NOMATCH
+C "\\" "[!\\\\-a]" NOMATCH
+C "_" "[!\\\\-a]" NOMATCH
+C "a" "[!\\\\-a]" NOMATCH
+C "-" "[!\\\\-a]" 0
+C "!" "[\\!-]" 0
+C "-" "[\\!-]" 0
+C "\\" "[\\!-]" NOMATCH
+C "Z" "[Z-\\\\]" 0
+C "[" "[Z-\\\\]" 0
+C "\\" "[Z-\\\\]" 0
+C "-" "[Z-\\\\]" NOMATCH
+C "Z" "[Z-\\]]" 0
+C "[" "[Z-\\]]" 0
+C "\\" "[Z-\\]]" 0
+C "]" "[Z-\\]]" 0
+C "-" "[Z-\\]]" NOMATCH
+
+# Following are tests outside the scope of IEEE 2003.2 since they are using
+# locales other than the C locale. The main focus of the tests is on the
+# handling of ranges and the recognition of character (vs bytes).
+de_DE.ISO-8859-1 "a" "[a-z]" 0
+de_DE.ISO-8859-1 "z" "[a-z]" 0
+de_DE.ISO-8859-1 "ä" "[a-z]" 0
+de_DE.ISO-8859-1 "ö" "[a-z]" 0
+de_DE.ISO-8859-1 "ü" "[a-z]" 0
+de_DE.ISO-8859-1 "A" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Z" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ä" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ö" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ü" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "a" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "z" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ä" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ö" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ü" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "A" "[A-Z]" 0
+de_DE.ISO-8859-1 "Z" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ä" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ö" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ü" "[A-Z]" 0
+de_DE.ISO-8859-1 "a" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "z" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ä" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ö" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ü" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "A" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Z" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ä" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ö" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ü" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "z" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ä" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ö" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ü" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "A" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Z" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ä" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ö" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ü" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "a" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "z" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ä" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ö" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ü" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "A" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Z" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ä" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ö" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ü" "[[:alpha:]]" 0
+
+de_DE.ISO-8859-1 "a" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=a=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=â=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=à=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=á=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=ä=]b]" NOMATCH
+
+de_DE.ISO-8859-1 "aa" "[[.a.]]a" 0
+de_DE.ISO-8859-1 "ba" "[[.a.]]a" NOMATCH
+
+
+# And with a multibyte character set.
+de_DE.UTF-8 "a" "[a-z]" 0
+de_DE.UTF-8 "z" "[a-z]" 0
+de_DE.UTF-8 "ä" "[a-z]" 0
+de_DE.UTF-8 "ö" "[a-z]" 0
+de_DE.UTF-8 "ü" "[a-z]" 0
+de_DE.UTF-8 "A" "[a-z]" NOMATCH
+de_DE.UTF-8 "Z" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ä" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ö" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ü" "[a-z]" NOMATCH
+de_DE.UTF-8 "a" "[A-Z]" NOMATCH
+de_DE.UTF-8 "z" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ä" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ö" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ü" "[A-Z]" NOMATCH
+de_DE.UTF-8 "A" "[A-Z]" 0
+de_DE.UTF-8 "Z" "[A-Z]" 0
+de_DE.UTF-8 "Ä" "[A-Z]" 0
+de_DE.UTF-8 "Ö" "[A-Z]" 0
+de_DE.UTF-8 "Ü" "[A-Z]" 0
+de_DE.UTF-8 "a" "[[:lower:]]" 0
+de_DE.UTF-8 "z" "[[:lower:]]" 0
+de_DE.UTF-8 "ä" "[[:lower:]]" 0
+de_DE.UTF-8 "ö" "[[:lower:]]" 0
+de_DE.UTF-8 "ü" "[[:lower:]]" 0
+de_DE.UTF-8 "A" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Z" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ä" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ö" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ü" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "a" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "z" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ä" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ö" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ü" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "A" "[[:upper:]]" 0
+de_DE.UTF-8 "Z" "[[:upper:]]" 0
+de_DE.UTF-8 "Ä" "[[:upper:]]" 0
+de_DE.UTF-8 "Ö" "[[:upper:]]" 0
+de_DE.UTF-8 "Ü" "[[:upper:]]" 0
+de_DE.UTF-8 "a" "[[:alpha:]]" 0
+de_DE.UTF-8 "z" "[[:alpha:]]" 0
+de_DE.UTF-8 "ä" "[[:alpha:]]" 0
+de_DE.UTF-8 "ö" "[[:alpha:]]" 0
+de_DE.UTF-8 "ü" "[[:alpha:]]" 0
+de_DE.UTF-8 "A" "[[:alpha:]]" 0
+de_DE.UTF-8 "Z" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ä" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ö" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ü" "[[:alpha:]]" 0
+
+de_DE.UTF-8 "a" "[[=a=]b]" 0
+de_DE.UTF-8 "â" "[[=a=]b]" 0
+de_DE.UTF-8 "à" "[[=a=]b]" 0
+de_DE.UTF-8 "á" "[[=a=]b]" 0
+de_DE.UTF-8 "ä" "[[=a=]b]" 0
+de_DE.UTF-8 "b" "[[=a=]b]" 0
+de_DE.UTF-8 "c" "[[=a=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=â=]b]" 0
+de_DE.UTF-8 "â" "[[=â=]b]" 0
+de_DE.UTF-8 "à" "[[=â=]b]" 0
+de_DE.UTF-8 "á" "[[=â=]b]" 0
+de_DE.UTF-8 "ä" "[[=â=]b]" 0
+de_DE.UTF-8 "b" "[[=â=]b]" 0
+de_DE.UTF-8 "c" "[[=â=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=à=]b]" 0
+de_DE.UTF-8 "â" "[[=à=]b]" 0
+de_DE.UTF-8 "à" "[[=à=]b]" 0
+de_DE.UTF-8 "á" "[[=à=]b]" 0
+de_DE.UTF-8 "ä" "[[=à=]b]" 0
+de_DE.UTF-8 "b" "[[=à=]b]" 0
+de_DE.UTF-8 "c" "[[=à=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=á=]b]" 0
+de_DE.UTF-8 "â" "[[=á=]b]" 0
+de_DE.UTF-8 "à" "[[=á=]b]" 0
+de_DE.UTF-8 "á" "[[=á=]b]" 0
+de_DE.UTF-8 "ä" "[[=á=]b]" 0
+de_DE.UTF-8 "b" "[[=á=]b]" 0
+de_DE.UTF-8 "c" "[[=á=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=ä=]b]" 0
+de_DE.UTF-8 "â" "[[=ä=]b]" 0
+de_DE.UTF-8 "à" "[[=ä=]b]" 0
+de_DE.UTF-8 "á" "[[=ä=]b]" 0
+de_DE.UTF-8 "ä" "[[=ä=]b]" 0
+de_DE.UTF-8 "b" "[[=ä=]b]" 0
+de_DE.UTF-8 "c" "[[=ä=]b]" NOMATCH
+
+de_DE.UTF-8 "aa" "[[.a.]]a" 0
+de_DE.UTF-8 "ba" "[[.a.]]a" NOMATCH
+
+
+# Test of GNU extensions.
+C "x" "x" 0 PATHNAME|LEADING_DIR
+C "x/y" "x" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x" 0 PATHNAME|LEADING_DIR
+C "x" "*" 0 PATHNAME|LEADING_DIR
+C "x/y" "*" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "*" 0 PATHNAME|LEADING_DIR
+C "x" "*x" 0 PATHNAME|LEADING_DIR
+C "x/y" "*x" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "*x" 0 PATHNAME|LEADING_DIR
+C "x" "x*" 0 PATHNAME|LEADING_DIR
+C "x/y" "x*" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x*" 0 PATHNAME|LEADING_DIR
+C "x" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x/y/z" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x" "x/y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "x/y" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x/y" 0 PATHNAME|LEADING_DIR
+C "x" "x?y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "x?y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y/z" "x?y" NOMATCH PATHNAME|LEADING_DIR
+
+# ksh style matching.
+C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH
+C "/dev/udp/129.22.8.102/45" "/dev/@(tcp|udp)/*/*" 0 PATHNAME|EXTMATCH
+C "12" "[1-9]*([0-9])" 0 EXTMATCH
+C "12abc" "[1-9]*([0-9])" NOMATCH EXTMATCH
+C "1" "[1-9]*([0-9])" 0 EXTMATCH
+C "07" "+([0-7])" 0 EXTMATCH
+C "0377" "+([0-7])" 0 EXTMATCH
+C "09" "+([0-7])" NOMATCH EXTMATCH
+C "paragraph" "para@(chute|graph)" 0 EXTMATCH
+C "paramour" "para@(chute|graph)" NOMATCH EXTMATCH
+C "para991" "para?([345]|99)1" 0 EXTMATCH
+C "para381" "para?([345]|99)1" NOMATCH EXTMATCH
+C "paragraph" "para*([0-9])" NOMATCH EXTMATCH
+C "para" "para*([0-9])" 0 EXTMATCH
+C "para13829383746592" "para*([0-9])" 0 EXTMATCH
+C "paragraph" "para+([0-9])" NOMATCH EXTMATCH
+C "para" "para+([0-9])" NOMATCH EXTMATCH
+C "para987346523" "para+([0-9])" 0 EXTMATCH
+C "paragraph" "para!(*.[0-9])" 0 EXTMATCH
+C "para.38" "para!(*.[0-9])" 0 EXTMATCH
+C "para.graph" "para!(*.[0-9])" 0 EXTMATCH
+C "para39" "para!(*.[0-9])" 0 EXTMATCH
+C "" "*(0|1|3|5|7|9)" 0 EXTMATCH
+C "137577991" "*(0|1|3|5|7|9)" 0 EXTMATCH
+C "2468" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH
+C "1358" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH
+C "file.c" "*.c?(c)" 0 EXTMATCH
+C "file.C" "*.c?(c)" NOMATCH EXTMATCH
+C "file.cc" "*.c?(c)" 0 EXTMATCH
+C "file.ccc" "*.c?(c)" NOMATCH EXTMATCH
+C "parse.y" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH
+C "shell.c" "!(*.c|*.h|Makefile.in|config*|README)" NOMATCH EXTMATCH
+C "Makefile" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH
+C "VMS.FILE;1" "*\;[1-9]*([0-9])" 0 EXTMATCH
+C "VMS.FILE;0" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "VMS.FILE;" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "VMS.FILE;139" "*\;[1-9]*([0-9])" 0 EXTMATCH
+C "VMS.FILE;1N" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "abcfefg" "ab**(e|f)" 0 EXTMATCH
+C "abcfefg" "ab**(e|f)g" 0 EXTMATCH
+C "ab" "ab*+(e|f)" NOMATCH EXTMATCH
+C "abef" "ab***ef" 0 EXTMATCH
+C "abef" "ab**" 0 EXTMATCH
+C "fofo" "*(f*(o))" 0 EXTMATCH
+C "ffo" "*(f*(o))" 0 EXTMATCH
+C "foooofo" "*(f*(o))" 0 EXTMATCH
+C "foooofof" "*(f*(o))" 0 EXTMATCH
+C "fooofoofofooo" "*(f*(o))" 0 EXTMATCH
+C "foooofof" "*(f+(o))" NOMATCH EXTMATCH
+C "xfoooofof" "*(f*(o))" NOMATCH EXTMATCH
+C "foooofofx" "*(f*(o))" NOMATCH EXTMATCH
+C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofooofoofofooo" "*(f*(o))" NOMATCH EXTMATCH
+C "foooxfooxfoxfooox" "*(f*(o)x)" 0 EXTMATCH
+C "foooxfooxofoxfooox" "*(f*(o)x)" NOMATCH EXTMATCH
+C "foooxfooxfxfooox" "*(f*(o)x)" 0 EXTMATCH
+C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxoo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxofo" "*(*(of*(o)x)o)" NOMATCH EXTMATCH
+C "ofoooxoofxoofoooxoofxooofxofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "aac" "*(@(a))a@(c)" 0 EXTMATCH
+C "ac" "*(@(a))a@(c)" 0 EXTMATCH
+C "c" "*(@(a))a@(c)" NOMATCH EXTMATCH
+C "aaac" "*(@(a))a@(c)" 0 EXTMATCH
+C "baaac" "*(@(a))a@(c)" NOMATCH EXTMATCH
+C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH
+C "abcd" "@(ab|a*@(b))*(c)d" 0 EXTMATCH
+C "acd" "@(ab|a*(b))*(c)d" 0 EXTMATCH
+C "abbcd" "@(ab|a*(b))*(c)d" 0 EXTMATCH
+C "effgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "efgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egzefffgzbcdij" "*(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egz" "@(b+(c)d|e+(f)g?|?(h)i@(j|k))" NOMATCH EXTMATCH
+C "ofoofo" "*(of+(o))" 0 EXTMATCH
+C "oxfoxoxfox" "*(oxf+(ox))" 0 EXTMATCH
+C "oxfoxfox" "*(oxf+(ox))" NOMATCH EXTMATCH
+C "ofoofo" "*(of+(o)|f)" 0 EXTMATCH
+C "foofoofo" "@(foo|f|fo)*(f|of+(o))" 0 EXTMATCH
+C "oofooofo" "*(of|oof+(o))" 0 EXTMATCH
+C "fffooofoooooffoofffooofff" "*(*(f)*(o))" 0 EXTMATCH
+C "fofoofoofofoo" "*(fo|foo)" 0 EXTMATCH
+C "foo" "!(x)" 0 EXTMATCH
+C "foo" "!(x)*" 0 EXTMATCH
+C "foo" "!(foo)" NOMATCH EXTMATCH
+C "foo" "!(foo)*" 0 EXTMATCH
+C "foobar" "!(foo)" 0 EXTMATCH
+C "foobar" "!(foo)*" 0 EXTMATCH
+C "moo.cow" "!(*.*).!(*.*)" 0 EXTMATCH
+C "mad.moo.cow" "!(*.*).!(*.*)" NOMATCH EXTMATCH
+C "mucca.pazza" "mu!(*(c))?.pa!(*(z))?" NOMATCH EXTMATCH
+C "fff" "!(f)" 0 EXTMATCH
+C "fff" "*(!(f))" 0 EXTMATCH
+C "fff" "+(!(f))" 0 EXTMATCH
+C "ooo" "!(f)" 0 EXTMATCH
+C "ooo" "*(!(f))" 0 EXTMATCH
+C "ooo" "+(!(f))" 0 EXTMATCH
+C "foo" "!(f)" 0 EXTMATCH
+C "foo" "*(!(f))" 0 EXTMATCH
+C "foo" "+(!(f))" 0 EXTMATCH
+C "f" "!(f)" NOMATCH EXTMATCH
+C "f" "*(!(f))" NOMATCH EXTMATCH
+C "f" "+(!(f))" NOMATCH EXTMATCH
+C "foot" "@(!(z*)|*x)" 0 EXTMATCH
+C "zoot" "@(!(z*)|*x)" NOMATCH EXTMATCH
+C "foox" "@(!(z*)|*x)" 0 EXTMATCH
+C "zoox" "@(!(z*)|*x)" 0 EXTMATCH
+C "foo" "*(!(foo)) 0 EXTMATCH
+C "foob" "!(foo)b*" NOMATCH EXTMATCH
+C "foobb" "!(foo)b*" 0 EXTMATCH
+C "[" "*([a[])" 0 EXTMATCH
+C "]" "*([]a[])" 0 EXTMATCH
+C "a" "*([]a[])" 0 EXTMATCH
+C "b" "*([!]a[])" 0 EXTMATCH
+C "[" "*([!]a[]|[[])" 0 EXTMATCH
+C "]" "*([!]a[]|[]])" 0 EXTMATCH
+C "[" "!([!]a[])" 0 EXTMATCH
+C "]" "!([!]a[])" 0 EXTMATCH
+C ")" "*([)])" 0 EXTMATCH
+C "*" "*([*(])" 0 EXTMATCH
+C "abcd" "*!(|a)cd" 0 EXTMATCH
+C "ab/.a" "+([abc])/*" NOMATCH EXTMATCH|PATHNAME|PERIOD
+C "" "" 0
+C "" "" 0 EXTMATCH
+C "" "*([abc])" 0 EXTMATCH
+C "" "?([abc])" 0 EXTMATCH
diff --git a/libc/posix/tst-fork.c b/libc/posix/tst-fork.c
new file mode 100644
index 000000000..a9d468ead
--- /dev/null
+++ b/libc/posix/tst-fork.c
@@ -0,0 +1,152 @@
+/* Tests for fork.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wait.h>
+
+
+static const char testdata[] = "This is a test";
+static const char testdata2[] = "And here we go again";
+
+
+int
+main (void)
+{
+ const char *tmpdir = getenv ("TMPDIR");
+ char buf[100];
+ size_t tmpdirlen;
+ char *name;
+ int fd;
+ pid_t pid;
+ pid_t ppid;
+ off_t off;
+ int status;
+
+ if (tmpdir == NULL || *tmpdir == '\0')
+ tmpdir = "/tmp";
+ tmpdirlen = strlen (tmpdir);
+
+ name = (char *) malloc (tmpdirlen + strlen ("/forkXXXXXX") + 1);
+ if (name == NULL)
+ error (EXIT_FAILURE, errno, "cannot allocate file name");
+
+ mempcpy (mempcpy (name, tmpdir, tmpdirlen),
+ "/forkXXXXXX", sizeof ("/forkXXXXXX"));
+
+ /* Open our test file. */
+ fd = mkstemp (name);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
+
+ /* Make sure it gets removed. */
+ unlink (name);
+
+ /* Write some data. */
+ if (write (fd, testdata, strlen (testdata)) != strlen (testdata))
+ error (EXIT_FAILURE, errno, "cannot write test data");
+
+ /* Get the position in the stream. */
+ off = lseek (fd, 0, SEEK_CUR);
+ if (off == (off_t) -1 || off != strlen (testdata))
+ error (EXIT_FAILURE, errno, "wrong file position");
+
+ /* Get the parent PID. */
+ ppid = getpid ();
+
+ /* Now fork of the process. */
+ pid = fork ();
+ if (pid == 0)
+ {
+ /* One little test first: the PID must have changed. */
+ if (getpid () == ppid)
+ error (EXIT_FAILURE, 0, "child and parent have same PID");
+
+ /* Test the `getppid' function. */
+ pid = getppid ();
+ if (pid == (pid_t) -1 ? errno != ENOSYS : pid != ppid)
+ error (EXIT_FAILURE, 0,
+ "getppid returned wrong PID (%ld, should be %ld)",
+ (long int) pid, (long int) ppid);
+
+ /* This is the child. First get the position of the descriptor. */
+ off = lseek (fd, 0, SEEK_CUR);
+ if (off == (off_t) -1 || off != strlen (testdata))
+ error (EXIT_FAILURE, errno, "wrong file position in child");
+
+ /* Reset the position. */
+ if (lseek (fd, 0, SEEK_SET) != 0)
+ error (EXIT_FAILURE, errno, "cannot reset position in child");
+
+ /* Read the data. */
+ if (read (fd, buf, sizeof buf) != strlen (testdata))
+ error (EXIT_FAILURE, errno, "cannot read data in child");
+
+ /* Compare the data. */
+ if (memcmp (buf, testdata, strlen (testdata)) != 0)
+ error (EXIT_FAILURE, 0, "data comparison failed in child");
+
+ /* Reset position again. */
+ if (lseek (fd, 0, SEEK_SET) != 0)
+ error (EXIT_FAILURE, errno, "cannot reset position again in child");
+
+ /* Write new data. */
+ if (write (fd, testdata2, strlen (testdata2)) != strlen (testdata2))
+ error (EXIT_FAILURE, errno, "cannot write new data in child");
+
+ /* Close the file. This must not remove it. */
+ close (fd);
+
+ _exit (0);
+ }
+ else if (pid < 0)
+ /* Something went wrong. */
+ error (EXIT_FAILURE, errno, "cannot fork");
+
+ /* Wait for the child. */
+ if (waitpid (pid, &status, 0) != pid)
+ error (EXIT_FAILURE, 0, "Oops, wrong test program terminated");
+
+ if (WTERMSIG (status) != 0)
+ error (EXIT_FAILURE, 0, "Child terminated incorrectly");
+ status = WEXITSTATUS (status);
+
+ if (status == 0)
+ {
+ /* Test whether the child wrote the right data. First test the
+ position. It must be the same as in the child. */
+ if (lseek (fd, 0, SEEK_CUR) != strlen (testdata2))
+ error (EXIT_FAILURE, 0, "file position not changed");
+
+ if (lseek (fd, 0, SEEK_SET) != 0)
+ error (EXIT_FAILURE, errno, "cannot reset file position");
+
+ if (read (fd, buf, sizeof buf) != strlen (testdata2))
+ error (EXIT_FAILURE, errno, "cannot read new data");
+
+ if (memcmp (buf, testdata2, strlen (testdata2)) != 0)
+ error (EXIT_FAILURE, 0, "new data not read correctly");
+ }
+
+ return status;
+}
diff --git a/libc/posix/tst-getaddrinfo.c b/libc/posix/tst-getaddrinfo.c
new file mode 100644
index 000000000..565621ed9
--- /dev/null
+++ b/libc/posix/tst-getaddrinfo.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+static int
+do_test (void)
+{
+ const int family[2] = { AF_INET, AF_INET6 };
+ int result = 0;
+ int gaierr;
+ size_t index;
+ struct addrinfo hints, *ai, *aitop;
+
+ for (index = 0; index < sizeof (family) / sizeof (family[0]); ++index)
+ {
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = family[index];
+ hints.ai_socktype = SOCK_STREAM;
+
+ gaierr = getaddrinfo (NULL, "54321", &hints, &aitop);
+ if (gaierr != 0)
+ {
+ gai_strerror (gaierr);
+ result = 1;
+ }
+ else
+ {
+ for (ai = aitop; ai != NULL; ai = ai->ai_next)
+ {
+ printf ("Should return family: %d. Returned: %d\n",
+ family[index], ai->ai_family);
+ result |= family[index] != ai->ai_family;
+ }
+
+ while (aitop != NULL)
+ {
+ ai = aitop;
+ aitop = aitop->ai_next;
+ freeaddrinfo (ai);
+ }
+ }
+ }
+
+ return result;
+}
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-getaddrinfo2.c b/libc/posix/tst-getaddrinfo2.c
new file mode 100644
index 000000000..13edca0a3
--- /dev/null
+++ b/libc/posix/tst-getaddrinfo2.c
@@ -0,0 +1,77 @@
+/* Test by David L Stevens <dlstevens@us.ibm.com> [BZ #358] */
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+static int
+do_test (void)
+{
+ const char portstr[] = "583";
+ int port = atoi (portstr);
+ struct addrinfo hints, *aires, *pai;
+ int rv;
+ int res = 1;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = AF_INET;
+ rv = getaddrinfo (NULL, portstr, &hints, &aires);
+ if (rv == 0)
+ {
+ struct sockaddr_in *psin = 0;
+ int got_tcp, got_udp;
+ int err = 0;
+
+ got_tcp = got_udp = 0;
+ for (pai = aires; pai; pai = pai->ai_next)
+ {
+ printf ("ai_family=%d, ai_addrlen=%d, ai_socktype=%d",
+ (int) pai->ai_family, (int) pai->ai_addrlen,
+ (int) pai->ai_socktype);
+ if (pai->ai_family == AF_INET)
+ printf (", port=%d",
+ ntohs (((struct sockaddr_in *) pai->ai_addr)->sin_port));
+ puts ("");
+
+ err |= pai->ai_family != AF_INET;
+ err |= pai->ai_addrlen != sizeof (struct sockaddr_in);
+ err |= pai->ai_addr == 0;
+ if (pai->ai_family == AF_INET)
+ err |=
+ ntohs (((struct sockaddr_in *) pai->ai_addr)->sin_port) != port;
+ got_tcp |= pai->ai_socktype == SOCK_STREAM;
+ got_udp |= pai->ai_socktype == SOCK_DGRAM;
+ if (err)
+ break;
+ }
+ if (err)
+ {
+ printf ("FAIL getaddrinfo IPv4 socktype 0,513: "
+ "fam %d alen %d addr %p addr/fam %d "
+ "addr/port %d H[%d]\n",
+ pai->ai_family, pai->ai_addrlen, psin,
+ psin ? psin->sin_family : 0,
+ psin ? psin->sin_port : 0,
+ psin ? htons (psin->sin_port) : 0);
+ }
+ else if (got_tcp && got_udp)
+ {
+ printf ("SUCCESS getaddrinfo IPv4 socktype 0,513\n");
+ res = 0;
+ }
+ else
+ printf ("FAIL getaddrinfo IPv4 socktype 0,513 TCP %d"
+ " UDP %d\n", got_tcp, got_udp);
+ freeaddrinfo (aires);
+ }
+ else
+ printf ("FAIL getaddrinfo IPv4 socktype 0,513 returns %d "
+ "(\"%s\")\n", rv, gai_strerror (rv));
+
+ return res;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-getaddrinfo3.c b/libc/posix/tst-getaddrinfo3.c
new file mode 100644
index 000000000..5077f311f
--- /dev/null
+++ b/libc/posix/tst-getaddrinfo3.c
@@ -0,0 +1,151 @@
+#include <mcheck.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ int result = 0;
+ struct addrinfo hints;
+ struct addrinfo *ai_res;
+ int s;
+
+#define T(no, fail, addr, fam, coraddr) \
+ s = getaddrinfo (addr, NULL, &hints, &ai_res); \
+ if (s != 0) \
+ { \
+ if (s != fail) \
+ { \
+ printf ("getaddrinfo test %d failed: %s\n", no, gai_strerror (s)); \
+ result = 1; \
+ } \
+ ai_res = NULL; \
+ } \
+ else if (fail) \
+ { \
+ printf ("getaddrinfo test %d should have failed but did not\n", no); \
+ result = 1; \
+ } \
+ else if (ai_res->ai_family != fam) \
+ { \
+ printf ("\
+getaddrinfo test %d return address of family %d, expected %d\n", \
+ no, ai_res->ai_family, fam); \
+ result = 1; \
+ } \
+ else if (fam == AF_INET) \
+ { \
+ if (ai_res->ai_addrlen != sizeof (struct sockaddr_in)) \
+ { \
+ printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \
+ no, (size_t) ai_res->ai_addrlen, \
+ sizeof (struct sockaddr_in)); \
+ result = 1; \
+ } \
+ else if (strcmp (coraddr, \
+ inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr))\
+ != 0) \
+ { \
+ printf ("getaddrinfo test %d: got value %s, expected %s\n", \
+ no, \
+ inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr), \
+ coraddr); \
+ result = 1; \
+ } \
+ } \
+ else \
+ { \
+ char buf[100]; \
+ \
+ if (ai_res->ai_addrlen != sizeof (struct sockaddr_in6)) \
+ { \
+ printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \
+ no, (size_t) ai_res->ai_addrlen, \
+ sizeof (struct sockaddr_in6)); \
+ result = 1; \
+ } \
+ else if (strcmp (coraddr, \
+ inet_ntop (AF_INET6, \
+ &((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr,\
+ buf, sizeof (buf))) \
+ != 0) \
+ { \
+ printf ("getaddrinfo test %d: got value %s, expected %s\n", \
+ no, \
+ inet_ntop (AF_INET6, \
+ & ((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr, \
+ buf, sizeof (buf)), \
+ coraddr); \
+ result = 1; \
+ } \
+ } \
+ if (ai_res != NULL && ai_res->ai_next != NULL) \
+ { \
+ puts ("expected only one result"); \
+ result = 1; \
+ } \
+ freeaddrinfo (ai_res)
+
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ T (1, 0, "127.0.0.1", AF_INET, "127.0.0.1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ T (2, 0, "127.0.0.1", AF_INET, "127.0.0.1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_V4MAPPED;
+ T (3, 0, "127.0.0.1", AF_INET6, "::ffff:127.0.0.1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ T (4, EAI_ADDRFAMILY, "127.0.0.1", AF_INET6, "");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ T (5, 0, "::1", AF_INET6, "::1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ T (6, EAI_ADDRFAMILY, "::1", AF_INET6, "");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ T (7, 0, "::1", AF_INET6, "::1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ T (8, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ T (9, 0, "::ffff:127.0.0.1", AF_INET, "127.0.0.1");
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ T (10, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1");
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-getconf.sh b/libc/posix/tst-getconf.sh
new file mode 100644
index 000000000..9630ebf4e
--- /dev/null
+++ b/libc/posix/tst-getconf.sh
@@ -0,0 +1,243 @@
+#! /bin/sh
+
+common_objpfx=$1; shift
+elf_objpfx=$1; shift
+if [ $# -eq 0 ]; then
+ # Static case.
+ runit() {
+ "$@"
+ }
+else
+ rtld_installed_name=$1; shift
+ runit() {
+ ${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} "$@"
+ }
+fi
+
+logfile=$common_objpfx/posix/tst-getconf.out
+
+# Since we use `sort' we must make sure to use the same locale everywhere.
+LC_ALL=C
+export LC_ALL
+LANG=C
+export LANG
+
+rm -f $logfile
+result=0
+while read name; do
+ echo -n "getconf $name: " >> $logfile
+ runit ${common_objpfx}posix/getconf "$name" 2>> $logfile >> $logfile
+ if test $? -ne 0; then
+ echo "*** $name FAILED" >> $logfile
+ result=1
+ fi
+done <<EOF
+AIO_LISTIO_MAX
+AIO_MAX
+AIO_PRIO_DELTA_MAX
+ARG_MAX
+ATEXIT_MAX
+BC_BASE_MAX
+BC_DIM_MAX
+BC_SCALE_MAX
+BC_STRING_MAX
+CHILD_MAX
+COLL_WEIGHTS_MAX
+DELAYTIMER_MAX
+EXPR_NEST_MAX
+HOST_NAME_MAX
+IOV_MAX
+LINE_MAX
+LOGIN_NAME_MAX
+NGROUPS_MAX
+MQ_OPEN_MAX
+MQ_PRIO_MAX
+OPEN_MAX
+_POSIX_ADVISORY_INFO
+_POSIX_BARRIERS
+_POSIX_ASYNCHRONOUS_IO
+_POSIX_BASE
+_POSIX_C_LANG_SUPPORT
+_POSIX_C_LANG_SUPPORT_R
+_POSIX_CLOCK_SELECTION
+_POSIX_CPUTIME
+_POSIX_DEVICE_IO
+_POSIX_DEVICE_SPECIFIC
+_POSIX_DEVICE_SPECIFIC_R
+_POSIX_FD_MGMT
+_POSIX_FIFO
+_POSIX_FILE_ATTRIBUTES
+_POSIX_FILE_LOCKING
+_POSIX_FILE_SYSTEM
+_POSIX_FSYNC
+_POSIX_JOB_CONTROL
+_POSIX_MAPPED_FILES
+_POSIX_MEMLOCK
+_POSIX_MEMLOCK_RANGE
+_POSIX_MEMORY_PROTECTION
+_POSIX_MESSAGE_PASSING
+_POSIX_MONOTONIC_CLOCK
+_POSIX_MULTI_PROCESS
+_POSIX_NETWORKING
+_POSIX_PIPE
+_POSIX_PRIORITIZED_IO
+_POSIX_PRIORITY_SCHEDULING
+_POSIX_READER_WRITER_LOCKS
+_POSIX_REALTIME_SIGNALS
+_POSIX_REGEXP
+_POSIX_SAVED_IDS
+_POSIX_SEMAPHORES
+_POSIX_SHARED_MEMORY_OBJECTS
+_POSIX_SHELL
+_POSIX_SIGNALS
+_POSIX_SINGLE_PROCESS
+_POSIX_SPAWN
+_POSIX_SPIN_LOCKS
+_POSIX_SPORADIC_SERVER
+_POSIX_SYNCHRONIZED_IO
+_POSIX_SYSTEM_DATABASE
+_POSIX_SYSTEM_DATABASE_R
+_POSIX_THREAD_ATTR_STACKADDR
+_POSIX_THREAD_ATTR_STACKSIZE
+_POSIX_THREAD_CPUTIME
+_POSIX_THREAD_PRIO_INHERIT
+_POSIX_THREAD_PRIO_PROTECT
+_POSIX_THREAD_PRIORITY_SCHEDULING
+_POSIX_THREAD_PROCESS_SHARED
+_POSIX_THREAD_SAFE_FUNCTIONS
+_POSIX_THREAD_SPORADIC_SERVER
+_POSIX_THREADS
+_POSIX_TIMEOUTS
+_POSIX_TIMERS
+_POSIX_TRACE
+_POSIX_TRACE_EVENT_FILTER
+_POSIX_TRACE_INHERIT
+_POSIX_TRACE_LOG
+_POSIX_TYPED_MEMORY_OBJECTS
+_POSIX_USER_GROUPS
+_POSIX_USER_GROUPS_R
+_POSIX_VERSION
+_POSIX_V6_ILP32_OFF32
+_POSIX_V6_ILP32_OFFBIG
+_POSIX_V6_LP64_OFF64
+_POSIX_V6_LPBIG_OFFBIG
+_POSIX_V6_WIDTH_RESTRICTED_ENVS
+POSIX2_C_BIND
+POSIX2_C_DEV
+POSIX2_C_VERSION
+POSIX2_CHAR_TERM
+POSIX2_FORT_DEV
+POSIX2_FORT_RUN
+POSIX2_LOCALEDEF
+POSIX2_PBS
+POSIX2_PBS_ACCOUNTING
+POSIX2_PBS_LOCATE
+POSIX2_PBS_MESSAGE
+POSIX2_PBS_TRACK
+POSIX2_SW_DEV
+POSIX2_UPE
+POSIX2_VERSION
+_REGEX_VERSION
+PAGE_SIZE
+PAGESIZE
+PTHREAD_DESTRUCTOR_ITERATIONS
+PTHREAD_KEYS_MAX
+PTHREAD_STACK_MIN
+PTHREAD_THREADS_MAX
+RE_DUP_MAX
+RTSIG_MAX
+SEM_NSEMS_MAX
+SEM_VALUE_MAX
+SIGQUEUE_MAX
+STREAM_MAX
+SYMLOOP_MAX
+TIMER_MAX
+TTY_NAME_MAX
+TZNAME_MAX
+_XBS5_ILP32_OFF32
+_XBS5_ILP32_OFFBIG
+_XBS5_LP64_OFF64
+_XBS5_LPBIG_OFFBIG
+_XOPEN_CRYPT
+_XOPEN_ENH_I18N
+_XOPEN_LEGACY
+_XOPEN_REALTIME
+_XOPEN_REALTIME_THREADS
+_XOPEN_SHM
+_XOPEN_UNIX
+_XOPEN_VERSION
+_XOPEN_XCU_VERSION
+PATH
+POSIX_V6_ILP32_OFF32_CFLAGS
+POSIX_V6_ILP32_OFF32_LDFLAGS
+POSIX_V6_ILP32_OFF32_LIBS
+POSIX_V6_ILP32_OFF32_LINTFLAGS
+POSIX_V6_ILP32_OFFBIG_CFLAGS
+POSIX_V6_ILP32_OFFBIG_LDFLAGS
+POSIX_V6_ILP32_OFFBIG_LIBS
+POSIX_V6_ILP32_OFFBIG_LINTFLAGS
+POSIX_V6_LP64_OFF64_CFLAGS
+POSIX_V6_LP64_OFF64_LDFLAGS
+POSIX_V6_LP64_OFF64_LIBS
+POSIX_V6_LP64_OFF64_LINTFLAGS
+POSIX_V6_LPBIG_OFFBIG_CFLAGS
+POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+POSIX_V6_LPBIG_OFFBIG_LIBS
+POSIX_V6_LPBIG_OFFBIG_LINTFLAGS
+XBS5_ILP32_OFF32_CFLAGS
+XBS5_ILP32_OFF32_LDFLAGS
+XBS5_ILP32_OFF32_LIBS
+XBS5_ILP32_OFF32_LINTFLAGS
+XBS5_ILP32_OFFBIG_CFLAGS
+XBS5_ILP32_OFFBIG_LDFLAGS
+XBS5_ILP32_OFFBIG_LIBS
+XBS5_ILP32_OFFBIG_LINTFLAGS
+XBS5_LP64_OFF64_CFLAGS
+XBS5_LP64_OFF64_LDFLAGS
+XBS5_LP64_OFF64_LIBS
+XBS5_LP64_OFF64_LINTFLAGS
+XBS5_LPBIG_OFFBIG_CFLAGS
+XBS5_LPBIG_OFFBIG_LDFLAGS
+XBS5_LPBIG_OFFBIG_LIBS
+XBS5_LPBIG_OFFBIG_LINTFLAGS
+EOF
+
+while read name; do
+ echo -n "getconf $name /: " >> $logfile
+ runit ${common_objpfx}posix/getconf "$name" / 2>> $logfile >> $logfile
+ if test $? -ne 0; then
+ echo "*** $name FAILED" >> $logfile
+ result=1
+ fi
+done <<EOF
+FILESIZEBITS
+LINK_MAX
+MAX_CANON
+MAX_INPUT
+NAME_MAX
+PATH_MAX
+PIPE_BUF
+POSIX_ALLOC_SIZE_MIN
+POSIX_REC_INCR_XFER_SIZE
+POSIX_REC_MAX_XFER_SIZE
+POSIX_REC_MIN_XFER_SIZE
+POSIX_REC_XFER_ALIGN
+SYMLINK_MAX
+_POSIX_CHOWN_RESTRICTED
+_POSIX_NO_TRUNC
+_POSIX_VDISABLE
+_POSIX_ASYNC_IO
+_POSIX_PRIO_IO
+_POSIX_SYNC_IO
+EOF
+
+exit $result
+
+# Preserve executable bits for this shell script.
+Local Variables:
+eval:(defun frobme () (set-file-modes buffer-file-name file-mode))
+eval:(make-local-variable 'file-mode)
+eval:(setq file-mode (file-modes (buffer-file-name)))
+eval:(make-local-variable 'after-save-hook)
+eval:(add-hook 'after-save-hook 'frobme)
+End:
diff --git a/libc/posix/tst-getlogin.c b/libc/posix/tst-getlogin.c
new file mode 100644
index 000000000..31b496e86
--- /dev/null
+++ b/libc/posix/tst-getlogin.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+ char *login;
+ int errors = 0;
+
+ login = getlogin ();
+ if (login == NULL)
+ puts ("getlogin returned NULL, no further tests");
+ else
+ {
+ char name[1024];
+ int ret;
+
+ printf ("getlogin returned: `%s'\n", login);
+
+ ret = getlogin_r (name, sizeof (name));
+ if (ret == 0)
+ {
+ printf ("getlogin_r returned: `%s'\n", name);
+ if (strcmp (name, login) != 0)
+ {
+ puts ("Error: getlogin and getlogin_r returned different names");
+ ++errors;
+ }
+ }
+ else
+ {
+ printf ("Error: getlogin_r returned: %d (%s)\n",
+ ret, strerror (ret));
+ ++errors;
+ }
+ }
+
+ return errors != 0;
+}
diff --git a/libc/posix/tst-gnuglob.c b/libc/posix/tst-gnuglob.c
new file mode 100644
index 000000000..72f3fa4a3
--- /dev/null
+++ b/libc/posix/tst-gnuglob.c
@@ -0,0 +1,445 @@
+/* Test the GNU extensions in glob which allow the user to provide callbacks
+ for the filesystem access functions.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <glob.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+
+// #define DEBUG
+#ifdef DEBUG
+# define PRINTF(fmt, args...) printf (fmt, ##args)
+#else
+# define PRINTF(fmt, args...)
+#endif
+
+
+static struct
+{
+ const char *name;
+ int level;
+ int type;
+} filesystem[] =
+{
+ { ".", 1, DT_DIR },
+ { "..", 1, DT_DIR },
+ { "file1lev1", 1, DT_REG },
+ { "file2lev1", 1, DT_UNKNOWN },
+ { "dir1lev1", 1, DT_UNKNOWN },
+ { ".", 2, DT_DIR },
+ { "..", 2, DT_DIR },
+ { "file1lev2", 2, DT_REG },
+ { "dir1lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { "dir2lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { ".foo", 3, DT_REG },
+ { "dir1lev3", 3, DT_DIR },
+ { ".", 4, DT_DIR },
+ { "..", 4, DT_DIR },
+ { "file1lev4", 4, DT_REG },
+ { "file1lev3", 3, DT_REG },
+ { "file2lev3", 3, DT_REG },
+ { "file2lev2", 2, DT_REG },
+ { "file3lev2", 2, DT_REG },
+ { "dir3lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { "file3lev3", 3, DT_REG },
+ { "file4lev3", 3, DT_REG },
+ { "dir2lev1", 1, DT_DIR },
+ { ".", 2, DT_DIR },
+ { "..", 2, DT_DIR },
+ { "dir1lev2", 2, DT_UNKNOWN },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { ".foo", 3, DT_REG },
+ { ".dir", 3, DT_DIR },
+ { ".", 4, DT_DIR },
+ { "..", 4, DT_DIR },
+ { "hidden", 4, DT_REG }
+};
+#define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
+
+
+typedef struct
+{
+ int level;
+ int idx;
+ struct dirent d;
+ char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+
+static long int
+find_file (const char *s)
+{
+ int level = 1;
+ long int idx = 0;
+
+ if (strcmp (s, ".") == 0)
+ return 0;
+
+ if (s[0] == '.' && s[1] == '/')
+ s += 2;
+
+ while (*s != '\0')
+ {
+ char *endp = strchrnul (s, '/');
+
+ PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
+
+ while (idx < nfiles && filesystem[idx].level >= level)
+ {
+ if (filesystem[idx].level == level
+ && memcmp (s, filesystem[idx].name, endp - s) == 0
+ && filesystem[idx].name[endp - s] == '\0')
+ break;
+ ++idx;
+ }
+
+ if (idx == nfiles || filesystem[idx].level < level)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (*endp == '\0')
+ return idx + 1;
+
+ if (filesystem[idx].type != DT_DIR
+ && (idx + 1 >= nfiles
+ || filesystem[idx].level >= filesystem[idx + 1].level))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ ++idx;
+
+ s = endp + 1;
+ ++level;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+
+static void *
+my_opendir (const char *s)
+{
+ long int idx = find_file (s);
+ my_DIR *dir;
+
+
+ if (idx == -1)
+ {
+ PRINTF ("my_opendir(\"%s\") == NULL\n", s);
+ return NULL;
+ }
+
+ dir = (my_DIR *) malloc (sizeof (my_DIR));
+ if (dir == NULL)
+ error (EXIT_FAILURE, errno, "cannot allocate directory handle");
+
+ dir->level = filesystem[idx].level;
+ dir->idx = idx;
+
+ PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
+ s, filesystem[idx].level, idx);
+
+ return dir;
+}
+
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+ my_DIR *dir = gdir;
+
+ if (dir->idx == -1)
+ {
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+ ++dir->idx;
+
+ if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+ {
+ dir->idx = -1;
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ dir->d.d_ino = dir->idx;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+ strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
+ dir->d.d_name);
+#else
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino,
+ dir->d.d_name);
+#endif
+
+ ++dir->idx;
+
+ return &dir->d;
+}
+
+
+static void
+my_closedir (void *dir)
+{
+ PRINTF ("my_closedir ()\n");
+ free (dir);
+}
+
+
+/* We use this function for lstat as well since we don't have any. */
+static int
+my_stat (const char *name, struct stat *st)
+{
+ long int idx = find_file (name);
+
+ if (idx == -1)
+ {
+ PRINTF ("my_stat (\"%s\", ...) = -1 (%s)\n", name, strerror (errno));
+ return -1;
+ }
+
+ memset (st, '\0', sizeof (*st));
+
+ if (filesystem[idx].type == DT_UNKNOWN)
+ st->st_mode = DTTOIF (idx + 1 < nfiles
+ && filesystem[idx].level < filesystem[idx + 1].level
+ ? DT_DIR : DT_REG) | 0777;
+ else
+ st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+
+ PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
+
+ return 0;
+}
+
+
+static const char *glob_errstring[] =
+{
+ [GLOB_NOSPACE] = "out of memory",
+ [GLOB_ABORTED] = "read error",
+ [GLOB_NOMATCH] = "no matches found"
+};
+#define nglob_errstring (sizeof (glob_errstring) / sizeof (glob_errstring[0]))
+
+
+static const char *
+flagstr (int flags)
+{
+ const char *strs[] =
+ {
+ "GLOB_ERR", "GLOB_MARK", "GLOB_NOSORT", "GLOB_DOOFSS", "GLOB_NOCHECK",
+ "GLOB_APPEND", "GLOB_NOESCAPE", "GLOB_PERIOD", "GLOB_MAGCHAR",
+ "GLOB_ALTDIRFUNC", "GLOB_BRACE", "GLOB_NOMAGIC", "GLOB_TILDE",
+ "GLOB_ONLYDIR", "GLOB_TILDECHECK"
+ };
+#define nstrs (sizeof (strs) / sizeof (strs[0]))
+ static char buf[100];
+ char *cp = buf;
+ int cnt;
+
+ for (cnt = 0; cnt < nstrs; ++cnt)
+ if (flags & (1 << cnt))
+ {
+ flags &= ~(1 << cnt);
+ if (cp != buf)
+ *cp++ = '|';
+ cp = stpcpy (cp, strs[cnt]);
+ }
+
+ if (flags != 0)
+ {
+ if (cp != buf)
+ *cp++ = '|';
+ sprintf (cp, "%#x", flags);
+ }
+
+ return buf;
+}
+
+
+static int
+test_result (const char *fmt, int flags, glob_t *gl, const char *str[])
+{
+ size_t cnt;
+ int result = 0;
+
+ printf ("results for glob (\"%s\", %s)\n", fmt, flagstr (flags));
+ for (cnt = 0; cnt < gl->gl_pathc && str[cnt] != NULL; ++cnt)
+ {
+ int ok = strcmp (gl->gl_pathv[cnt], str[cnt]) == 0;
+ const char *errstr = "";
+
+ if (! ok)
+ {
+ size_t inner;
+
+ for (inner = 0; str[inner] != NULL; ++inner)
+ if (strcmp (gl->gl_pathv[cnt], str[inner]) == 0)
+ break;
+
+ if (str[inner] == NULL)
+ errstr = ok ? "" : " *** WRONG";
+ else
+ errstr = ok ? "" : " * wrong position";
+
+ result = 1;
+ }
+
+ printf (" %s%s\n", gl->gl_pathv[cnt], errstr);
+ }
+ puts ("");
+
+ if (str[cnt] != NULL || cnt < gl->gl_pathc)
+ {
+ puts (" *** incorrect number of entries");
+ result = 1;
+ }
+
+ return result;
+}
+
+
+int
+main (void)
+{
+ glob_t gl;
+ int errval;
+ int result = 0;
+ const char *fmt;
+ int flags;
+
+ mtrace ();
+
+ memset (&gl, '\0', sizeof (gl));
+
+ gl.gl_closedir = my_closedir;
+ gl.gl_readdir = my_readdir;
+ gl.gl_opendir = my_opendir;
+ gl.gl_lstat = my_stat;
+ gl.gl_stat = my_stat;
+
+#define test(a, b, c...) \
+ fmt = a; \
+ flags = b; \
+ errval = glob (fmt, flags, NULL, &gl); \
+ if (errval != 0) \
+ { \
+ printf ("glob (\"%s\", %s) failed: %s\n", fmt, flagstr (flags), \
+ errval >= 0 && errval < nglob_errstring \
+ ? glob_errstring[errval] : "???"); \
+ result = 1; \
+ } \
+ else \
+ result |= test_result (fmt, flags, &gl, (const char *[]) { c, NULL })
+
+ test ("*/*/*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir2lev2/dir1lev3",
+ "dir1lev1/dir2lev2/file1lev3",
+ "dir1lev1/dir2lev2/file2lev3",
+ "dir1lev1/dir3lev2/file3lev3",
+ "dir1lev1/dir3lev2/file4lev3");
+
+ test ("*/*/*", GLOB_ALTDIRFUNC | GLOB_PERIOD,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir2lev2/dir1lev3",
+ "dir1lev1/dir2lev2/file1lev3",
+ "dir1lev1/dir2lev2/file2lev3",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir1lev1/dir3lev2/file3lev3",
+ "dir1lev1/dir3lev2/file4lev3",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*/*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*1*/*2*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*1*/*1*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ globfree (&gl);
+
+ return result;
+}
diff --git a/libc/posix/tst-mmap.c b/libc/posix/tst-mmap.c
new file mode 100644
index 000000000..c03acf5e1
--- /dev/null
+++ b/libc/posix/tst-mmap.c
@@ -0,0 +1,197 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+int
+main (void)
+{
+ int result = 0;
+ FILE *fp;
+ size_t c;
+ char buf[1000];
+ int fd;
+ unsigned char *ptr;
+ size_t ps = sysconf (_SC_PAGESIZE);
+ void *mem;
+
+ /* Create a file and put some data in it. */
+ fp = tmpfile ();
+ if (fp == NULL)
+ {
+ printf ("Cannot create temporary file: %m\n");
+ return 1;
+ }
+ fd = fileno (fp);
+
+ for (c = 0; c < sizeof (buf); ++c)
+ buf[c] = '0' + (c % 10);
+
+ for (c = 0; c < (ps * 4) / sizeof (buf); ++c)
+ if (fwrite (buf, 1, sizeof (buf), fp) != sizeof (buf))
+ {
+ printf ("`fwrite' failed: %m\n");
+ return 1;
+ }
+ fflush (fp);
+ assert (ps + 1000 < c * sizeof (buf));
+
+ /* First try something which is not allowed: map at an offset which is
+ not modulo the pagesize. */
+ ptr = mmap (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps - 1);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at offset with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* Try the same for mmap64. */
+ ptr = mmap64 (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps - 1);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at offset with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* And the same for private mapping. */
+ ptr = mmap (NULL, 1000, PROT_READ, MAP_PRIVATE, fd, ps - 1);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at offset with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* Try the same for mmap64. */
+ ptr = mmap64 (NULL, 1000, PROT_READ, MAP_PRIVATE, fd, ps - 1);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at offset with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* Get a valid address. */
+ mem = malloc (2 * ps);
+ if (mem != NULL)
+ {
+ /* Now we map at an address which is not mod pagesize. */
+ ptr = mmap (mem + 1, 1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, ps);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at address with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* Try the same for mmap64. */
+ ptr = mmap64 (mem + 1, 1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, ps);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at address with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* And again for MAP_PRIVATE. */
+ ptr = mmap (mem + 1, 1000, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ps);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at address with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ /* Try the same for mmap64. */
+ ptr = mmap64 (mem + 1, 1000, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ps);
+ if (ptr != MAP_FAILED)
+ {
+ puts ("mapping at address with mod pagesize != 0 succeeded!");
+ result = 1;
+ }
+ else if (errno != EINVAL && errno != ENOSYS)
+ {
+ puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)");
+ result = 1;
+ }
+
+ free (mem);
+ }
+
+ /* Now map the memory and see whether the content of the mapped area
+ is correct. */
+ ptr = mmap (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps);
+ if (ptr == MAP_FAILED)
+ {
+ if (errno != ENOSYS)
+ {
+ printf ("cannot mmap file: %m\n");
+ result = 1;
+ }
+ }
+ else
+ {
+ for (c = ps; c < ps + 1000; ++c)
+ if (ptr[c - ps] != '0' + (c % 10))
+ {
+ printf ("wrong data mapped at offset %zd\n", c);
+ result = 1;
+ }
+ }
+
+ /* And for mmap64. */
+ ptr = mmap64 (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps);
+ if (ptr == MAP_FAILED)
+ {
+ if (errno != ENOSYS)
+ {
+ printf ("cannot mmap file: %m\n");
+ result = 1;
+ }
+ }
+ else
+ {
+ for (c = ps; c < ps + 1000; ++c)
+ if (ptr[c - ps] != '0' + (c % 10))
+ {
+ printf ("wrong data mapped at offset %zd\n", c);
+ result = 1;
+ }
+ }
+
+ /* That's it. */
+ return result;
+}
diff --git a/libc/posix/tst-nanosleep.c b/libc/posix/tst-nanosleep.c
new file mode 100644
index 000000000..0fa0135bc
--- /dev/null
+++ b/libc/posix/tst-nanosleep.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+/* Test that nanosleep() does sleep. */
+static int
+do_test (void)
+{
+ /* Current time. */
+ struct timeval tv1;
+ (void) gettimeofday (&tv1, NULL);
+
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+ /* At least one second must have passed. */
+ struct timeval tv2;
+ (void) gettimeofday (&tv2, NULL);
+
+ tv2.tv_sec -= tv1.tv_sec;
+ tv2.tv_usec -= tv1.tv_usec;
+ if (tv2.tv_usec < 0)
+ --tv2.tv_sec;
+
+ if (tv2.tv_sec < 1)
+ {
+ puts ("nanosleep didn't sleep long enough");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-nice.c b/libc/posix/tst-nice.c
new file mode 100644
index 000000000..2b16cecca
--- /dev/null
+++ b/libc/posix/tst-nice.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+/* Test that nice() does not incorrectly return 0. */
+static int
+do_test (void)
+{
+ int ret;
+ const int incr = 10;
+ int old;
+
+ /* Discover current nice value. */
+ errno = 0;
+ old = nice (0);
+ if (old == -1 && errno != 0)
+ {
+ printf ("break: nice(%d) return: %d, %m\n", 0, old);
+ return 1;
+ }
+
+ /* Nice ourselves up. */
+ errno = 0;
+ ret = nice (incr);
+ if (ret == -1 && errno != 0)
+ {
+ printf ("break: nice(%d) return: %d, %m\n", incr, ret);
+ return 1;
+ }
+
+ /* Check for return value being zero when it shouldn't. Cannot simply
+ check for expected value since nice values are capped at 2^n-1.
+ But we assume that we didn't start at the cap and so should have
+ increased some. */
+ if (ret <= old)
+ {
+ printf ("FAIL: retval (%d) of nice(%d) != %d\n", ret, incr, old + incr);
+ return 1;
+ }
+
+ printf ("PASS: nice(%d) from %d return: %d\n", incr, old, ret);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-pcre.c b/libc/posix/tst-pcre.c
new file mode 100644
index 000000000..3780a0945
--- /dev/null
+++ b/libc/posix/tst-pcre.c
@@ -0,0 +1,241 @@
+/* Regular expression tests.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+ char *line = NULL;
+ size_t line_len = 0;
+ ssize_t len;
+ FILE *f;
+ char *pattern = NULL, *string = NULL;
+ regmatch_t rm[20];
+ size_t pattern_alloced = 0, string_alloced = 0;
+ int ignorecase = 0;
+ int pattern_valid = 0, rm_valid = 0;
+ size_t linenum;
+
+ mtrace ();
+
+ if (argc < 2)
+ {
+ fprintf (stderr, "Missing test filename\n");
+ return 1;
+ }
+
+ f = fopen (argv[1], "r");
+ if (f == NULL)
+ {
+ fprintf (stderr, "Couldn't open %s\n", argv[1]);
+ return 1;
+ }
+
+ if ((len = getline (&line, &line_len, f)) <= 0
+ || strncmp (line, "# PCRE", 6) != 0)
+ {
+ fprintf (stderr, "Not a PCRE test file\n");
+ fclose (f);
+ free (line);
+ return 1;
+ }
+
+ linenum = 1;
+
+ while ((len = getline (&line, &line_len, f)) > 0)
+ {
+ char *p;
+ unsigned long num;
+
+ ++linenum;
+
+ if (line[len - 1] == '\n')
+ line[--len] = '\0';
+
+ if (line[0] == '#')
+ continue;
+
+ if (line[0] == '\0')
+ {
+ /* End of test. */
+ ignorecase = 0;
+ pattern_valid = 0;
+ rm_valid = 0;
+ continue;
+ }
+
+ if (line[0] == '/')
+ {
+ /* Pattern. */
+ p = strrchr (line + 1, '/');
+
+ pattern_valid = 0;
+ rm_valid = 0;
+ if (p == NULL)
+ {
+ printf ("%zd: Invalid pattern line: %s\n", linenum, line);
+ ret = 1;
+ continue;
+ }
+
+ if (p[1] == 'i' && p[2] == '\0')
+ ignorecase = 1;
+ else if (p[1] != '\0')
+ {
+ printf ("%zd: Invalid pattern line: %s\n", linenum, line);
+ ret = 1;
+ continue;
+ }
+
+ if (pattern_alloced < (size_t) (p - line))
+ {
+ pattern = realloc (pattern, p - line);
+ if (pattern == NULL)
+ {
+ printf ("%zd: Cannot record pattern: %m\n", linenum);
+ ret = 1;
+ break;
+ }
+ pattern_alloced = p - line;
+ }
+
+ memcpy (pattern, line + 1, p - line - 1);
+ pattern[p - line - 1] = '\0';
+ pattern_valid = 1;
+ continue;
+ }
+
+ if (strncmp (line, " ", 4) == 0)
+ {
+ regex_t re;
+ int n;
+
+ if (!pattern_valid)
+ {
+ printf ("%zd: No previous valid pattern %s\n", linenum, line);
+ continue;
+ }
+
+ if (string_alloced < (size_t) (len - 3))
+ {
+ string = realloc (string, len - 3);
+ if (string == NULL)
+ {
+ printf ("%zd: Cannot record search string: %m\n", linenum);
+ ret = 1;
+ break;
+ }
+ string_alloced = len - 3;
+ }
+
+ memcpy (string, line + 4, len - 3);
+
+ n = regcomp (&re, pattern,
+ REG_EXTENDED | (ignorecase ? REG_ICASE : 0));
+ if (n != 0)
+ {
+ char buf[500];
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("%zd: regcomp failed for %s: %s\n",
+ linenum, pattern, buf);
+ ret = 1;
+ continue;
+ }
+
+ if (regexec (&re, string, 20, rm, 0))
+ {
+ rm[0].rm_so = -1;
+ rm[0].rm_eo = -1;
+ }
+
+ regfree (&re);
+ rm_valid = 1;
+ continue;
+ }
+
+ if (!rm_valid)
+ {
+ printf ("%zd: No preceeding pattern or search string\n", linenum);
+ ret = 1;
+ continue;
+ }
+
+ if (strcmp (line, "No match") == 0)
+ {
+ if (rm[0].rm_so != -1 || rm[0].rm_eo != -1)
+ {
+ printf ("%zd: /%s/ on %s unexpectedly matched %d..%d\n",
+ linenum, pattern, string, rm[0].rm_so, rm[0].rm_eo);
+ ret = 1;
+ }
+
+ continue;
+ }
+
+ p = line;
+ if (*p == ' ')
+ ++p;
+
+ num = strtoul (p, &p, 10);
+ if (num >= 20 || *p != ':' || p[1] != ' ')
+ {
+ printf ("%zd: Invalid line %s\n", linenum, line);
+ ret = 1;
+ continue;
+ }
+
+ if (rm[num].rm_so == -1 || rm[num].rm_eo == -1)
+ {
+ if (strcmp (p + 2, "<unset>") != 0)
+ {
+ printf ("%zd: /%s/ on %s unexpectedly failed to match register %ld %d..%d\n",
+ linenum, pattern, string, num,
+ rm[num].rm_so, rm[num].rm_eo);
+ ret = 1;
+ }
+ continue;
+ }
+
+ if (rm[num].rm_eo < rm[num].rm_so
+ || rm[num].rm_eo - rm[num].rm_so != len - (p + 2 - line)
+ || strncmp (p + 2, string + rm[num].rm_so,
+ rm[num].rm_eo - rm[num].rm_so) != 0)
+ {
+ printf ("%zd: /%s/ on %s unexpectedly failed to match %s for register %ld %d..%d\n",
+ linenum, pattern, string, p + 2, num,
+ rm[num].rm_so, rm[num].rm_eo);
+ ret = 1;
+ continue;
+ }
+ }
+
+ free (pattern);
+ free (string);
+ free (line);
+ fclose (f);
+ return ret;
+}
diff --git a/libc/posix/tst-preadwrite.c b/libc/posix/tst-preadwrite.c
new file mode 100644
index 000000000..281044858
--- /dev/null
+++ b/libc/posix/tst-preadwrite.c
@@ -0,0 +1,105 @@
+/* Tests for pread and pwrite.
+ Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* Allow testing of the 64-bit versions as well. */
+#ifndef PREAD
+# define PREAD pread
+# define PWRITE pwrite
+#endif
+
+#define STRINGIFY(s) STRINGIFY2 (s)
+#define STRINGIFY2(s) #s
+
+/* Prototype for our test function. */
+extern void do_prepare (int argc, char *argv[]);
+extern int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+#define PREPARE do_prepare
+
+/* We might need a bit longer timeout. */
+#define TIMEOUT 20 /* sec */
+
+/* This defines the `main' function and some more. */
+#include <test-skeleton.c>
+
+/* These are for the temporary file we generate. */
+char *name;
+int fd;
+
+void
+do_prepare (int argc, char *argv[])
+{
+ char name_len;
+
+#define FNAME FNAME2(TRUNCATE)
+#define FNAME2(s) "/" STRINGIFY(s) "XXXXXX"
+
+ name_len = strlen (test_dir);
+ name = malloc (name_len + sizeof (FNAME));
+ if (name == NULL)
+ error (EXIT_FAILURE, errno, "cannot allocate file name");
+ mempcpy (mempcpy (name, test_dir, name_len), FNAME, sizeof (FNAME));
+ add_temp_file (name);
+
+ /* Open our test file. */
+ fd = mkstemp (name);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
+}
+
+
+int
+do_test (int argc, char *argv[])
+{
+ char buf[1000];
+ char res[1000];
+ int i;
+
+ memset (buf, '\0', sizeof (buf));
+ memset (res, '\xff', sizeof (res));
+
+ if (write (fd, buf, sizeof (buf)) != sizeof (buf))
+ error (EXIT_FAILURE, errno, "during write");
+
+ for (i = 100; i < 200; ++i)
+ buf[i] = i;
+ if (PWRITE (fd, buf + 100, 100, 100) != 100)
+ error (EXIT_FAILURE, errno, "during %s", STRINGIFY (PWRITE));
+
+ for (i = 450; i < 600; ++i)
+ buf[i] = i;
+ if (PWRITE (fd, buf + 450, 150, 450) != 150)
+ error (EXIT_FAILURE, errno, "during %s", STRINGIFY (PWRITE));
+
+ if (PREAD (fd, res, sizeof (buf) - 50, 50) != sizeof (buf) - 50)
+ error (EXIT_FAILURE, errno, "during %s", STRINGIFY (PREAD));
+
+ close (fd);
+ unlink (name);
+
+ return memcmp (buf + 50, res, sizeof (buf) - 50);
+}
diff --git a/libc/posix/tst-preadwrite64.c b/libc/posix/tst-preadwrite64.c
new file mode 100644
index 000000000..57098e864
--- /dev/null
+++ b/libc/posix/tst-preadwrite64.c
@@ -0,0 +1,24 @@
+/* Tests for pread64 and pwrite64.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define PREAD pread64
+#define PWRITE pwrite64
+
+#include "tst-preadwrite.c"
diff --git a/libc/posix/tst-regex.c b/libc/posix/tst-regex.c
new file mode 100644
index 000000000..6a71e1239
--- /dev/null
+++ b/libc/posix/tst-regex.c
@@ -0,0 +1,508 @@
+/* Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include "spawn_int.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <iconv.h>
+#include <locale.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <regex.h>
+
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+static clockid_t cl;
+static int use_clock;
+#endif
+static iconv_t cd;
+static char *mem;
+static char *umem;
+static size_t memlen;
+static size_t umemlen;
+static int timing;
+
+static int test_expr (const char *expr, int expected, int expectedicase);
+static int run_test (const char *expr, const char *mem, size_t memlen,
+ int icase, int expected);
+static int run_test_backwards (const char *expr, const char *mem,
+ size_t memlen, int icase, int expected);
+
+
+int
+main (int argc, char *argv[])
+{
+ const char *file;
+ int fd;
+ struct stat st;
+ int result;
+ char *inmem;
+ char *outmem;
+ size_t inlen;
+ size_t outlen;
+ static const struct option options[] =
+ {
+ {"timing",no_argument, &timing, 1 },
+ {NULL, 0, NULL, 0 }
+ };
+
+ mtrace ();
+
+ while (getopt_long (argc, argv, "", options, NULL) >= 0);
+
+ /* Make the content of the file available in memory. */
+ file = "../ChangeLog.8";
+ fd = open (file, O_RDONLY);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, "cannot open %s", basename (file));
+
+ if (fstat (fd, &st) != 0)
+ error (EXIT_FAILURE, errno, "cannot stat %s", basename (file));
+ memlen = st.st_size;
+
+ mem = (char *) malloc (memlen + 1);
+ if (mem == NULL)
+ error (EXIT_FAILURE, errno, "while allocating buffer");
+
+ if ((size_t) read (fd, mem, memlen) != memlen)
+ error (EXIT_FAILURE, 0, "cannot read entire file");
+ mem[memlen] = '\0';
+
+ close (fd);
+
+ /* We have to convert a few things from Latin-1 to UTF-8. */
+ cd = iconv_open ("UTF-8", "ISO-8859-1");
+ if (cd == (iconv_t) -1)
+ error (EXIT_FAILURE, errno, "cannot get conversion descriptor");
+
+ /* For the second test we have to convert the file content to UTF-8.
+ Since the text is mostly ASCII it should be enough to allocate
+ twice as much memory for the UTF-8 text than for the Latin-1
+ text. */
+ umem = (char *) calloc (2, memlen);
+ if (umem == NULL)
+ error (EXIT_FAILURE, errno, "while allocating buffer");
+
+ inmem = mem;
+ inlen = memlen;
+ outmem = umem;
+ outlen = 2 * memlen - 1;
+ iconv (cd, &inmem, &inlen, &outmem, &outlen);
+ umemlen = outmem - umem;
+ if (inlen != 0)
+ error (EXIT_FAILURE, errno, "cannot convert buffer");
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+# if _POSIX_CPUTIME == 0
+ if (sysconf (_SC_CPUTIME) < 0)
+ use_clock = 0;
+ else
+# endif
+ /* See whether we can use the CPU clock. */
+ use_clock = clock_getcpuclockid (0, &cl) == 0;
+#endif
+
+#ifdef DEBUG
+ re_set_syntax (RE_DEBUG);
+#endif
+
+ /* Run the actual tests. All tests are run in a single-byte and a
+ multi-byte locale. */
+ result = test_expr ("[äáàâéèêíìîñöóòôüúùû]", 2, 2);
+ result |= test_expr ("G.ran", 2, 3);
+ result |= test_expr ("G.\\{1\\}ran", 2, 3);
+ result |= test_expr ("G.*ran", 3, 44);
+ result |= test_expr ("[äáàâ]", 0, 0);
+ result |= test_expr ("Uddeborg", 2, 2);
+ result |= test_expr (".Uddeborg", 2, 2);
+
+ /* Free the resources. */
+ free (umem);
+ iconv_close (cd);
+ free (mem);
+
+ return result;
+}
+
+
+static int
+test_expr (const char *expr, int expected, int expectedicase)
+{
+ int result;
+ char *inmem;
+ char *outmem;
+ size_t inlen;
+ size_t outlen;
+ char *uexpr;
+
+ /* First test: search with an ISO-8859-1 locale. */
+ if (setlocale (LC_ALL, "de_DE.ISO-8859-1") == NULL)
+ error (EXIT_FAILURE, 0, "cannot set locale de_DE.ISO-8859-1");
+
+ printf ("\nTest \"%s\" with 8-bit locale\n", expr);
+ result = run_test (expr, mem, memlen, 0, expected);
+ printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr);
+ result |= run_test (expr, mem, memlen, 1, expectedicase);
+ printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr);
+ result |= run_test_backwards (expr, mem, memlen, 0, expected);
+ printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
+ expr);
+ result |= run_test_backwards (expr, mem, memlen, 1, expectedicase);
+
+ /* Second test: search with an UTF-8 locale. */
+ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+ error (EXIT_FAILURE, 0, "cannot set locale de_DE.UTF-8");
+
+ inmem = (char *) expr;
+ inlen = strlen (expr);
+ outlen = inlen * MB_CUR_MAX;
+ outmem = uexpr = alloca (outlen + 1);
+ memset (outmem, '\0', outlen + 1);
+ iconv (cd, &inmem, &inlen, &outmem, &outlen);
+ if (inlen != 0)
+ error (EXIT_FAILURE, errno, "cannot convert expression");
+
+ /* Run the tests. */
+ printf ("\nTest \"%s\" with multi-byte locale\n", expr);
+ result |= run_test (uexpr, umem, umemlen, 0, expected);
+ printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr);
+ result |= run_test (uexpr, umem, umemlen, 1, expectedicase);
+ printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr);
+ result |= run_test_backwards (uexpr, umem, umemlen, 0, expected);
+ printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
+ expr);
+ result |= run_test_backwards (uexpr, umem, umemlen, 1, expectedicase);
+
+ return result;
+}
+
+
+static int
+run_test (const char *expr, const char *mem, size_t memlen, int icase,
+ int expected)
+{
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ struct timespec start;
+ struct timespec finish;
+#endif
+ regex_t re;
+ int err;
+ size_t offset;
+ int cnt;
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ if (use_clock && !timing)
+ use_clock = clock_gettime (cl, &start) == 0;
+#endif
+
+ err = regcomp (&re, expr, REG_NEWLINE | (icase ? REG_ICASE : 0));
+ if (err != REG_NOERROR)
+ {
+ char buf[200];
+ regerror (err, &re, buf, sizeof buf);
+ error (EXIT_FAILURE, 0, "cannot compile expression: %s", buf);
+ }
+
+ cnt = 0;
+ offset = 0;
+ assert (mem[memlen] == '\0');
+ while (offset < memlen)
+ {
+ regmatch_t ma[1];
+ const char *sp;
+ const char *ep;
+
+ err = regexec (&re, mem + offset, 1, ma, 0);
+ if (err == REG_NOMATCH)
+ break;
+
+ if (err != REG_NOERROR)
+ {
+ char buf[200];
+ regerror (err, &re, buf, sizeof buf);
+ error (EXIT_FAILURE, 0, "cannot use expression: %s", buf);
+ }
+
+ assert (ma[0].rm_so >= 0);
+ sp = mem + offset + ma[0].rm_so;
+ while (sp > mem && sp[-1] != '\n')
+ --sp;
+
+ ep = mem + offset + ma[0].rm_so;
+ while (*ep != '\0' && *ep != '\n')
+ ++ep;
+
+ printf ("match %d: \"%.*s\"\n", ++cnt, (int) (ep - sp), sp);
+
+ offset = ep + 1 - mem;
+ }
+
+ regfree (&re);
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ if (use_clock && !timing)
+ {
+ use_clock = clock_gettime (cl, &finish) == 0;
+ if (use_clock)
+ {
+ if (finish.tv_nsec < start.tv_nsec)
+ {
+ finish.tv_nsec -= start.tv_nsec - 1000000000;
+ finish.tv_sec -= 1 + start.tv_sec;
+ }
+ else
+ {
+ finish.tv_nsec -= start.tv_nsec;
+ finish.tv_sec -= start.tv_sec;
+ }
+
+ printf ("elapsed time: %ld.%09ld sec\n",
+ finish.tv_sec, finish.tv_nsec);
+ }
+ }
+
+ if (use_clock && timing)
+ {
+ struct timespec mintime = { .tv_sec = 24 * 60 * 60 };
+
+ for (int i = 0; i < 10; ++i)
+ {
+ offset = 0;
+ use_clock = clock_gettime (cl, &start) == 0;
+
+ if (!use_clock)
+ continue;
+
+ err = regcomp (&re, expr, REG_NEWLINE | (icase ? REG_ICASE : 0));
+ if (err != REG_NOERROR)
+ continue;
+
+ while (offset < memlen)
+ {
+ regmatch_t ma[1];
+
+ err = regexec (&re, mem + offset, 1, ma, 0);
+ if (err != REG_NOERROR)
+ break;
+
+ offset += ma[0].rm_eo;
+ }
+
+ regfree (&re);
+
+ use_clock = clock_gettime (cl, &finish) == 0;
+ if (use_clock)
+ {
+ if (finish.tv_nsec < start.tv_nsec)
+ {
+ finish.tv_nsec -= start.tv_nsec - 1000000000;
+ finish.tv_sec -= 1 + start.tv_sec;
+ }
+ else
+ {
+ finish.tv_nsec -= start.tv_nsec;
+ finish.tv_sec -= start.tv_sec;
+ }
+ if (finish.tv_sec < mintime.tv_sec
+ || (finish.tv_sec == mintime.tv_sec
+ && finish.tv_nsec < mintime.tv_nsec))
+ mintime = finish;
+ }
+ }
+ printf ("elapsed time: %ld.%09ld sec\n",
+ mintime.tv_sec, mintime.tv_nsec);
+ }
+#endif
+
+ /* Return an error if the number of matches found is not match we
+ expect. */
+ return cnt != expected;
+}
+
+
+static int
+run_test_backwards (const char *expr, const char *mem, size_t memlen,
+ int icase, int expected)
+{
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ struct timespec start;
+ struct timespec finish;
+#endif
+ struct re_pattern_buffer re;
+ const char *err;
+ size_t offset;
+ int cnt;
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ if (use_clock && !timing)
+ use_clock = clock_gettime (cl, &start) == 0;
+#endif
+
+ re_set_syntax ((RE_SYNTAX_POSIX_BASIC & ~RE_DOT_NEWLINE)
+ | RE_HAT_LISTS_NOT_NEWLINE
+ | (icase ? RE_ICASE : 0));
+
+ memset (&re, 0, sizeof (re));
+ re.fastmap = malloc (256);
+ if (re.fastmap == NULL)
+ error (EXIT_FAILURE, errno, "cannot allocate fastmap");
+
+ err = re_compile_pattern (expr, strlen (expr), &re);
+ if (err != NULL)
+ error (EXIT_FAILURE, 0, "cannot compile expression: %s", err);
+
+ if (re_compile_fastmap (&re))
+ error (EXIT_FAILURE, 0, "couldn't compile fastmap");
+
+ cnt = 0;
+ offset = memlen;
+ assert (mem[memlen] == '\0');
+ while (offset <= memlen)
+ {
+ int start;
+ const char *sp;
+ const char *ep;
+
+ start = re_search (&re, mem, memlen, offset, -offset, NULL);
+ if (start == -1)
+ break;
+
+ if (start == -2)
+ error (EXIT_FAILURE, 0, "internal error in re_search");
+
+ sp = mem + start;
+ while (sp > mem && sp[-1] != '\n')
+ --sp;
+
+ ep = mem + start;
+ while (*ep != '\0' && *ep != '\n')
+ ++ep;
+
+ printf ("match %d: \"%.*s\"\n", ++cnt, (int) (ep - sp), sp);
+
+ offset = sp - 1 - mem;
+ }
+
+ regfree (&re);
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ if (use_clock && !timing)
+ {
+ use_clock = clock_gettime (cl, &finish) == 0;
+ if (use_clock)
+ {
+ if (finish.tv_nsec < start.tv_nsec)
+ {
+ finish.tv_nsec -= start.tv_nsec - 1000000000;
+ finish.tv_sec -= 1 + start.tv_sec;
+ }
+ else
+ {
+ finish.tv_nsec -= start.tv_nsec;
+ finish.tv_sec -= start.tv_sec;
+ }
+
+ printf ("elapsed time: %ld.%09ld sec\n",
+ finish.tv_sec, finish.tv_nsec);
+ }
+ }
+
+ if (use_clock && timing)
+ {
+ struct timespec mintime = { .tv_sec = 24 * 60 * 60 };
+
+ for (int i = 0; i < 10; ++i)
+ {
+ offset = memlen;
+ use_clock = clock_gettime (cl, &start) == 0;
+
+ if (!use_clock)
+ continue;
+
+ memset (&re, 0, sizeof (re));
+ re.fastmap = malloc (256);
+ if (re.fastmap == NULL)
+ continue;
+
+ err = re_compile_pattern (expr, strlen (expr), &re);
+ if (err != NULL)
+ continue;
+
+ if (re_compile_fastmap (&re))
+ {
+ regfree (&re);
+ continue;
+ }
+
+ while (offset <= memlen)
+ {
+ int start;
+ const char *sp;
+
+ start = re_search (&re, mem, memlen, offset, -offset, NULL);
+ if (start < -1)
+ break;
+
+ sp = mem + start;
+ while (sp > mem && sp[-1] != '\n')
+ --sp;
+
+ offset = sp - 1 - mem;
+ }
+
+ regfree (&re);
+
+ use_clock = clock_gettime (cl, &finish) == 0;
+ if (use_clock)
+ {
+ if (finish.tv_nsec < start.tv_nsec)
+ {
+ finish.tv_nsec -= start.tv_nsec - 1000000000;
+ finish.tv_sec -= 1 + start.tv_sec;
+ }
+ else
+ {
+ finish.tv_nsec -= start.tv_nsec;
+ finish.tv_sec -= start.tv_sec;
+ }
+ if (finish.tv_sec < mintime.tv_sec
+ || (finish.tv_sec == mintime.tv_sec
+ && finish.tv_nsec < mintime.tv_nsec))
+ mintime = finish;
+ }
+ }
+ printf ("elapsed time: %ld.%09ld sec\n",
+ mintime.tv_sec, mintime.tv_nsec);
+ }
+#endif
+
+ /* Return an error if the number of matches found is not match we
+ expect. */
+ return cnt != expected;
+}
diff --git a/libc/posix/tst-regex2.c b/libc/posix/tst-regex2.c
new file mode 100644
index 000000000..0d82c2acd
--- /dev/null
+++ b/libc/posix/tst-regex2.c
@@ -0,0 +1,249 @@
+#include <fcntl.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+static clockid_t cl;
+static int use_clock;
+#endif
+
+static int
+do_test (void)
+{
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+# if _POSIX_CPUTIME == 0
+ if (sysconf (_SC_CPUTIME) < 0)
+ use_clock = 0;
+ else
+# endif
+ /* See whether we can use the CPU clock. */
+ use_clock = clock_getcpuclockid (0, &cl) == 0;
+#endif
+
+ static const char *pat[] = {
+ ".?.?.?.?.?.?.?Log\\.13",
+ "(.?)(.?)(.?)(.?)(.?)(.?)(.?)Log\\.13",
+ "((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
+ "((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
+ "((((((((((.?))))))))))Log\\.13" };
+
+ int fd = open ("../ChangeLog.14", O_RDONLY);
+ if (fd < 0)
+ {
+ printf ("Couldn't open ChangeLog.14: %m\n");
+ return 1;
+ }
+
+ struct stat64 st;
+ if (fstat64 (fd, &st) < 0)
+ {
+ printf ("Couldn't fstat ChangeLog.14: %m\n");
+ return 1;
+ }
+
+ char *buf = malloc (st.st_size + 1);
+ if (buf == NULL)
+ {
+ printf ("Couldn't allocate buffer: %m\n");
+ return 1;
+ }
+
+ if (read (fd, buf, st.st_size) != (ssize_t) st.st_size)
+ {
+ puts ("Couldn't read ChangeLog.14");
+ return 1;
+ }
+
+ close (fd);
+ buf[st.st_size] = '\0';
+
+ setlocale (LC_ALL, "de_DE.UTF-8");
+
+ char *string = buf;
+ size_t len = st.st_size;
+
+#ifndef WHOLE_FILE_TIMING
+ /* Don't search the whole file normally, it takes too long. */
+ if (len > 500000 + 64)
+ {
+ string += 500000;
+ len -= 500000;
+ }
+#endif
+
+ for (int testno = 0; testno < 4; ++testno)
+ for (int i = 0; i < sizeof (pat) / sizeof (pat[0]); ++i)
+ {
+ printf ("test %d pattern %d", testno, i);
+
+ regex_t rbuf;
+ struct re_pattern_buffer rpbuf;
+ int err;
+ if (testno < 2)
+ {
+ err = regcomp (&rbuf, pat[i],
+ REG_EXTENDED | (testno ? REG_NOSUB : 0));
+ if (err != 0)
+ {
+ putchar ('\n');
+ char errstr[300];
+ regerror (err, &rbuf, errstr, sizeof (errstr));
+ puts (errstr);
+ return err;
+ }
+ }
+ else
+ {
+ re_set_syntax (RE_SYNTAX_POSIX_EGREP
+ | (testno == 3 ? RE_NO_SUB : 0));
+
+ memset (&rpbuf, 0, sizeof (rpbuf));
+ const char *s = re_compile_pattern (pat[i], strlen (pat[i]),
+ &rpbuf);
+ if (s != NULL)
+ {
+ printf ("\n%s\n", s);
+ return 1;
+ }
+
+ /* Just so that this can be tested with earlier glibc as well. */
+ if (testno == 3)
+ rpbuf.no_sub = 1;
+ }
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ struct timespec start, stop;
+ if (use_clock)
+ use_clock = clock_gettime (cl, &start) == 0;
+#endif
+
+ if (testno < 2)
+ {
+ regmatch_t pmatch[71];
+ err = regexec (&rbuf, string, 71, pmatch, 0);
+ if (err == REG_NOMATCH)
+ {
+ puts ("\nregexec failed");
+ return 1;
+ }
+
+ if (testno == 0)
+ {
+ if (pmatch[0].rm_eo != pmatch[0].rm_so + 13
+ || pmatch[0].rm_eo > len
+ || pmatch[0].rm_so < len - 100
+ || strncmp (string + pmatch[0].rm_so,
+ " ChangeLog.13 for earlier changes",
+ sizeof " ChangeLog.13 for earlier changes" - 1)
+ != 0)
+ {
+ puts ("\nregexec without REG_NOSUB did not find the correct match");
+ return 1;
+ }
+
+ if (i > 0)
+ for (int j = 0, l = 1; j < 7; ++j)
+ for (int k = 0; k < (i == 1 ? 1 : 10); ++k, ++l)
+ if (pmatch[l].rm_so != pmatch[0].rm_so + j
+ || pmatch[l].rm_eo != pmatch[l].rm_so + 1)
+ {
+ printf ("\npmatch[%d] incorrect\n", l);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ struct re_registers regs;
+
+ memset (&regs, 0, sizeof (regs));
+ int match = re_search (&rpbuf, string, len, 0, len,
+ &regs);
+ if (match < 0)
+ {
+ puts ("\nre_search failed");
+ return 1;
+ }
+
+ if (match + 13 > len
+ || match < len - 100
+ || strncmp (string + match,
+ " ChangeLog.13 for earlier changes",
+ sizeof " ChangeLog.13 for earlier changes" - 1)
+ != 0)
+ {
+ puts ("\nre_search did not find the correct match");
+ return 1;
+ }
+
+ if (testno == 2)
+ {
+ if (regs.num_regs != 2 + (i == 0 ? 0 : i == 1 ? 7 : 70))
+ {
+ printf ("\nincorrect num_regs %d\n", regs.num_regs);
+ return 1;
+ }
+
+ if (regs.start[0] != match || regs.end[0] != match + 13)
+ {
+ printf ("\nincorrect regs.{start,end}[0] = { %d, %d}\n",
+ regs.start[0], regs.end[0]);
+ return 1;
+ }
+
+ if (regs.start[regs.num_regs - 1] != -1
+ || regs.end[regs.num_regs - 1] != -1)
+ {
+ puts ("\nincorrect regs.{start,end}[num_regs - 1]");
+ return 1;
+ }
+
+ if (i > 0)
+ for (int j = 0, l = 1; j < 7; ++j)
+ for (int k = 0; k < (i == 1 ? 1 : 10); ++k, ++l)
+ if (regs.start[l] != match + j
+ || regs.end[l] != regs.start[l] + 1)
+ {
+ printf ("\nregs.{start,end}[%d] incorrect\n", l);
+ return 1;
+ }
+ }
+ }
+
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+ if (use_clock)
+ use_clock = clock_gettime (cl, &stop) == 0;
+ if (use_clock)
+ {
+ stop.tv_sec -= start.tv_sec;
+ if (stop.tv_nsec < start.tv_nsec)
+ {
+ stop.tv_sec--;
+ stop.tv_nsec += 1000000000 - start.tv_nsec;
+ }
+ else
+ stop.tv_nsec -= start.tv_nsec;
+ printf (": %ld.%09lds\n", (long) stop.tv_sec, (long) stop.tv_nsec);
+ }
+ else
+#endif
+ putchar ('\n');
+
+ if (testno < 2)
+ regfree (&rbuf);
+ else
+ regfree (&rpbuf);
+ }
+
+ return 0;
+}
+
+#define TIMEOUT 20
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-regexloc.c b/libc/posix/tst-regexloc.c
new file mode 100644
index 000000000..8ef941cf2
--- /dev/null
+++ b/libc/posix/tst-regexloc.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <spawn.h>
+#include "spawn_int.h"
+
+#include <sys/types.h>
+#include <regex.h>
+#include <locale.h>
+#include <stdio.h>
+
+int
+main (int argc, char *argv[])
+{
+ regex_t re;
+ regmatch_t mat[1];
+ int res = 1;
+
+ if (setlocale (LC_ALL, "de_DE.ISO-8859-1") == NULL)
+ puts ("cannot set locale");
+ else if (regcomp (&re, "[a-f]*", 0) != REG_NOERROR)
+ puts ("cannot compile expression \"[a-f]*\"");
+ else if (regexec (&re, "abcdefCDEF", 1, mat, 0) == REG_NOMATCH)
+ puts ("no match");
+ else
+ {
+ printf ("match from %d to %d\n", mat[0].rm_so, mat[0].rm_eo);
+ res = mat[0].rm_so != 0 || mat[0].rm_eo != 6;
+ }
+
+ return res;
+}
diff --git a/libc/posix/tst-rfc3484-2.c b/libc/posix/tst-rfc3484-2.c
new file mode 100644
index 000000000..2536da8f8
--- /dev/null
+++ b/libc/posix/tst-rfc3484-2.c
@@ -0,0 +1,145 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <ifaddrs.h>
+
+/* Internal definitions used in the libc code. */
+#define __getservbyname_r getservbyname_r
+#define __socket socket
+#define __getsockname getsockname
+#define __inet_aton inet_aton
+#define __gethostbyaddr_r gethostbyaddr_r
+#define __gethostbyname2_r gethostbyname2_r
+
+void
+attribute_hidden
+__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
+{
+ *p1 = *p2 = true;
+ *in6ai = NULL;
+ *in6ailen = 0;
+}
+int
+__idna_to_ascii_lz (const char *input, char **output, int flags)
+{
+ return 0;
+}
+int
+__idna_to_unicode_lzlz (const char *input, char **output, int flags)
+{
+ return 0;
+}
+
+#include "../sysdeps/posix/getaddrinfo.c"
+
+service_user *__nss_hosts_database attribute_hidden;
+
+
+/* This is the beginning of the real test code. The above defines
+ (among other things) the function rfc3484_sort. */
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define h(n) n
+#else
+# define h(n) __bswap_constant_32 (n)
+#endif
+
+
+ssize_t
+__getline (char **lineptr, size_t *n, FILE *s)
+{
+ *lineptr = NULL;
+ *n = 0;
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ labels = default_labels;
+ precedence = default_precedence;
+
+ struct sockaddr_in so1;
+ so1.sin_family = AF_INET;
+ so1.sin_addr.s_addr = h (0xc0a85f19);
+
+ struct sockaddr_in sa1;
+ sa1.sin_family = AF_INET;
+ sa1.sin_addr.s_addr = h (0xe0a85f19);
+
+ struct addrinfo ai1;
+ ai1.ai_family = AF_INET;
+ ai1.ai_addr = (struct sockaddr *) &sa1;
+
+ struct sockaddr_in6 so2;
+ so2.sin6_family = AF_INET6;
+ so2.sin6_addr.s6_addr32[0] = h (0xfec01234);
+ so2.sin6_addr.s6_addr32[1] = 1;
+ so2.sin6_addr.s6_addr32[2] = 1;
+ so2.sin6_addr.s6_addr32[3] = 1;
+
+ struct sockaddr_in6 sa2;
+ sa2.sin6_family = AF_INET6;
+ sa2.sin6_addr.s6_addr32[0] = h (0x07d10001);
+ sa2.sin6_addr.s6_addr32[1] = 1;
+ sa2.sin6_addr.s6_addr32[2] = 1;
+ sa2.sin6_addr.s6_addr32[3] = 1;
+
+ struct addrinfo ai2;
+ ai2.ai_family = AF_INET6;
+ ai2.ai_addr = (struct sockaddr *) &sa2;
+
+
+ struct sort_result results[2];
+
+ results[0].dest_addr = &ai1;
+ results[0].got_source_addr = true;
+ results[0].source_addr_len = sizeof (so1);
+ results[0].source_addr_flags = 0;
+ memcpy (&results[0].source_addr, &so1, sizeof (so1));
+
+ results[1].dest_addr = &ai2;
+ results[1].got_source_addr = true;
+ results[1].source_addr_len = sizeof (so2);
+ results[1].source_addr_flags = 0;
+ memcpy (&results[1].source_addr, &so2, sizeof (so2));
+
+
+ qsort (results, 2, sizeof (results[0]), rfc3484_sort);
+
+ int result = 0;
+ if (results[0].dest_addr->ai_family == AF_INET6)
+ {
+ puts ("wrong order in first test");
+ result |= 1;
+ }
+
+
+ /* And again, this time with the reverse starting order. */
+ results[1].dest_addr = &ai1;
+ results[1].got_source_addr = true;
+ results[1].source_addr_len = sizeof (so1);
+ results[1].source_addr_flags = 0;
+ memcpy (&results[1].source_addr, &so1, sizeof (so1));
+
+ results[0].dest_addr = &ai2;
+ results[0].got_source_addr = true;
+ results[0].source_addr_len = sizeof (so2);
+ results[0].source_addr_flags = 0;
+ memcpy (&results[0].source_addr, &so2, sizeof (so2));
+
+
+ qsort (results, 2, sizeof (results[0]), rfc3484_sort);
+
+ if (results[0].dest_addr->ai_family == AF_INET6)
+ {
+ puts ("wrong order in second test");
+ result |= 1;
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-rfc3484.c b/libc/posix/tst-rfc3484.c
new file mode 100644
index 000000000..2e74e9737
--- /dev/null
+++ b/libc/posix/tst-rfc3484.c
@@ -0,0 +1,114 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <ifaddrs.h>
+
+/* Internal definitions used in the libc code. */
+#define __getservbyname_r getservbyname_r
+#define __socket socket
+#define __getsockname getsockname
+#define __inet_aton inet_aton
+#define __gethostbyaddr_r gethostbyaddr_r
+#define __gethostbyname2_r gethostbyname2_r
+
+void
+attribute_hidden
+__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
+{
+ *p1 = *p2 = true;
+ *in6ai = NULL;
+ *in6ailen = 0;
+}
+int
+__idna_to_ascii_lz (const char *input, char **output, int flags)
+{
+ return 0;
+}
+int
+__idna_to_unicode_lzlz (const char *input, char **output, int flags)
+{
+ return 0;
+}
+
+#include "../sysdeps/posix/getaddrinfo.c"
+
+service_user *__nss_hosts_database attribute_hidden;
+
+
+/* This is the beginning of the real test code. The above defines
+ (among other things) the function rfc3484_sort. */
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define h(n) n
+#else
+# define h(n) __bswap_constant_32 (n)
+#endif
+
+struct sockaddr_in addrs[] =
+{
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a86d1d) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a85d03) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a82c3d) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a86002) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a802f3) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a80810) } },
+ { .sin_family = AF_INET, .sin_addr = { h (0xc0a85e02) } }
+};
+#define naddrs (sizeof (addrs) / sizeof (addrs[0]))
+static struct addrinfo ais[naddrs];
+static struct sort_result results[naddrs];
+
+static int expected[naddrs] =
+ {
+ 6, 1, 0, 3, 2, 4, 5
+ };
+
+
+ssize_t
+__getline (char **lineptr, size_t *n, FILE *s)
+{
+ *lineptr = NULL;
+ *n = 0;
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ labels = default_labels;
+ precedence = default_precedence;
+
+ struct sockaddr_in so;
+ so.sin_family = AF_INET;
+ so.sin_addr.s_addr = h (0xc0a85f19);
+
+ for (int i = 0; i < naddrs; ++i)
+ {
+ ais[i].ai_family = AF_INET;
+ ais[i].ai_addr = (struct sockaddr *) &addrs[i];
+ results[i].dest_addr = &ais[i];
+ results[i].got_source_addr = true;
+ memcpy(&results[i].source_addr, &so, sizeof (so));
+ results[i].source_addr_len = sizeof (so);
+ results[i].source_addr_flags = 0;
+ }
+
+ qsort (results, naddrs, sizeof (results[0]), rfc3484_sort);
+
+ int result = 0;
+ for (int i = 0; i < naddrs; ++i)
+ {
+ struct in_addr addr = ((struct sockaddr_in *) (results[i].dest_addr->ai_addr))->sin_addr;
+
+ int here = memcmp (&addr, &addrs[expected[i]].sin_addr,
+ sizeof (struct in_addr));
+ printf ("[%d] = %s: %s\n", i, inet_ntoa (addr), here ? "FAIL" : "OK");
+ result |= here;
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-rxspencer.c b/libc/posix/tst-rxspencer.c
new file mode 100644
index 000000000..a68bab2de
--- /dev/null
+++ b/libc/posix/tst-rxspencer.c
@@ -0,0 +1,562 @@
+/* Regular expression tests.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <mcheck.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <getopt.h>
+
+static void
+replace_special_chars (char *str)
+{
+ for (; (str = strpbrk (str, "NTSZ")) != NULL; ++str)
+ switch (*str)
+ {
+ case 'N': *str = '\n'; break;
+ case 'T': *str = '\t'; break;
+ case 'S': *str = ' '; break;
+ case 'Z': *str = '\0'; break;
+ }
+}
+
+static void
+glibc_re_syntax (char *str)
+{
+ char *p, *end = strchr (str, '\0') + 1;
+
+ /* Replace [[:<:]] with \< and [[:>:]] with \>. */
+ for (p = str; (p = strstr (p, "[[:")) != NULL; )
+ if ((p[3] == '<' || p[3] == '>') && strncmp (p + 4, ":]]", 3) == 0)
+ {
+ p[0] = '\\';
+ p[1] = p[3];
+ memmove (p + 2, p + 7, end - p - 7);
+ end -= 5;
+ p += 2;
+ }
+ else
+ p += 3;
+}
+
+static char *
+mb_replace (char *dst, const char c)
+{
+ switch (c)
+ {
+ /* Replace a with \'a and A with \'A. */
+ case 'a':
+ *dst++ = '\xc3';
+ *dst++ = '\xa1';
+ break;
+ case 'A':
+ *dst++ = '\xc3';
+ *dst++ = '\x81';
+ break;
+ /* Replace b with \v{c} and B with \v{C}. */
+ case 'b':
+ *dst++ = '\xc4';
+ *dst++ = '\x8d';
+ break;
+ case 'B':
+ *dst++ = '\xc4';
+ *dst++ = '\x8c';
+ break;
+ /* Replace c with \v{d} and C with \v{D}. */
+ case 'c':
+ *dst++ = '\xc4';
+ *dst++ = '\x8f';
+ break;
+ case 'C':
+ *dst++ = '\xc4';
+ *dst++ = '\x8e';
+ break;
+ /* Replace d with \'e and D with \'E. */
+ case 'd':
+ *dst++ = '\xc3';
+ *dst++ = '\xa9';
+ break;
+ case 'D':
+ *dst++ = '\xc3';
+ *dst++ = '\x89';
+ break;
+ }
+ return dst;
+}
+
+static char *
+mb_frob_string (const char *str, const char *letters)
+{
+ char *ret, *dst;
+ const char *src;
+
+ if (str == NULL)
+ return NULL;
+
+ ret = malloc (2 * strlen (str) + 1);
+ if (ret == NULL)
+ return NULL;
+
+ for (src = str, dst = ret; *src; ++src)
+ if (strchr (letters, *src))
+ dst = mb_replace (dst, *src);
+ else
+ *dst++ = *src;
+ *dst = '\0';
+ return ret;
+}
+
+/* Like mb_frob_string, but don't replace anything between
+ [: and :], [. and .] or [= and =] or characters escaped
+ with a backslash. */
+
+static char *
+mb_frob_pattern (const char *str, const char *letters)
+{
+ char *ret, *dst;
+ const char *src;
+ int in_class = 0, escaped = 0;
+
+ if (str == NULL)
+ return NULL;
+
+ ret = malloc (2 * strlen (str) + 1);
+ if (ret == NULL)
+ return NULL;
+
+ for (src = str, dst = ret; *src; ++src)
+ if (*src == '\\')
+ {
+ escaped ^= 1;
+ *dst++ = *src;
+ }
+ else if (escaped)
+ {
+ escaped = 0;
+ *dst++ = *src;
+ continue;
+ }
+ else if (!in_class && strchr (letters, *src))
+ dst = mb_replace (dst, *src);
+ else
+ {
+ if (!in_class && *src == '[' && strchr (":.=", src[1]))
+ in_class = 1;
+ else if (in_class && *src == ']' && strchr (":.=", src[-1]))
+ in_class = 0;
+ *dst++ = *src;
+ }
+ *dst = '\0';
+ return ret;
+}
+
+static int
+check_match (regmatch_t *rm, int idx, const char *string,
+ const char *match, const char *fail)
+{
+ if (match[0] == '-' && match[1] == '\0')
+ {
+ if (rm[idx].rm_so == -1 && rm[idx].rm_eo == -1)
+ return 0;
+ printf ("%s rm[%d] unexpectedly matched\n", fail, idx);
+ return 1;
+ }
+
+ if (rm[idx].rm_so == -1 || rm[idx].rm_eo == -1)
+ {
+ printf ("%s rm[%d] unexpectedly did not match\n", fail, idx);
+ return 1;
+ }
+
+ if (match[0] == '@')
+ {
+ if (rm[idx].rm_so != rm[idx].rm_eo)
+ {
+ printf ("%s rm[%d] not empty\n", fail, idx);
+ return 1;
+ }
+
+ if (strncmp (string + rm[idx].rm_so, match + 1, strlen (match + 1) ?: 1))
+ {
+ printf ("%s rm[%d] not matching %s\n", fail, idx, match);
+ return 1;
+ }
+ return 0;
+ }
+
+ if (rm[idx].rm_eo - rm[idx].rm_so != strlen (match)
+ || strncmp (string + rm[idx].rm_so, match,
+ rm[idx].rm_eo - rm[idx].rm_so))
+ {
+ printf ("%s rm[%d] not matching %s\n", fail, idx, match);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+test (const char *pattern, int cflags, const char *string, int eflags,
+ char *expect, char *matches, const char *fail)
+{
+ regex_t re;
+ regmatch_t rm[10];
+ int n, ret = 0;
+
+ n = regcomp (&re, pattern, cflags);
+ if (n != 0)
+ {
+ char buf[500];
+ if (eflags == -1)
+ {
+ static struct { reg_errcode_t code; const char *name; } codes []
+#define C(x) { REG_##x, #x }
+ = { C(NOERROR), C(NOMATCH), C(BADPAT), C(ECOLLATE),
+ C(ECTYPE), C(EESCAPE), C(ESUBREG), C(EBRACK),
+ C(EPAREN), C(EBRACE), C(BADBR), C(ERANGE),
+ C(ESPACE), C(BADRPT) };
+
+ for (int i = 0; i < sizeof (codes) / sizeof (codes[0]); ++i)
+ if (n == codes[i].code)
+ {
+ if (strcmp (string, codes[i].name))
+ {
+ printf ("%s regcomp returned REG_%s (expected REG_%s)\n",
+ fail, codes[i].name, string);
+ return 1;
+ }
+ return 0;
+ }
+
+ printf ("%s regcomp return value REG_%d\n", fail, n);
+ return 1;
+ }
+
+ regerror (n, &re, buf, sizeof (buf));
+ printf ("%s regcomp failed: %s\n", fail, buf);
+ return 1;
+ }
+
+ if (eflags == -1)
+ {
+ regfree (&re);
+
+ /* The test case file assumes something only guaranteed by the
+ rxspencer regex implementation. Namely that for empty
+ expressions regcomp() return REG_EMPTY. This is not the case
+ for us and so we ignore this error. */
+ if (strcmp (string, "EMPTY") == 0)
+ return 0;
+
+ printf ("%s regcomp unexpectedly succeeded\n", fail);
+ return 1;
+ }
+
+ if (regexec (&re, string, 10, rm, eflags))
+ {
+ regfree (&re);
+ if (expect == NULL)
+ return 0;
+ printf ("%s regexec failed\n", fail);
+ return 1;
+ }
+
+ regfree (&re);
+
+ if (expect == NULL)
+ {
+ printf ("%s regexec unexpectedly succeeded\n", fail);
+ return 1;
+ }
+
+ if (cflags & REG_NOSUB)
+ return 0;
+
+ ret = check_match (rm, 0, string, expect, fail);
+ if (matches == NULL)
+ return ret;
+
+ for (n = 1; ret == 0 && n < 10; ++n)
+ {
+ char *p = NULL;
+
+ if (matches)
+ {
+ p = strchr (matches, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+ ret = check_match (rm, n, string, matches ?: "-", fail);
+ if (p)
+ {
+ *p = ',';
+ matches = p + 1;
+ }
+ else
+ matches = NULL;
+ }
+
+ return ret;
+}
+
+static int
+mb_test (const char *pattern, int cflags, const char *string, int eflags,
+ char *expect, const char *matches, const char *letters,
+ const char *fail)
+{
+ char *pattern_mb = mb_frob_pattern (pattern, letters);
+ const char *string_mb
+ = eflags == -1 ? string : mb_frob_string (string, letters);
+ char *expect_mb = mb_frob_string (expect, letters);
+ char *matches_mb = mb_frob_string (matches, letters);
+ int ret = 0;
+
+ if (!pattern_mb || !string_mb
+ || (expect && !expect_mb) || (matches && !matches_mb))
+ {
+ printf ("%s %m", fail);
+ ret = 1;
+ }
+ else
+ ret = test (pattern_mb, cflags, string_mb, eflags, expect_mb,
+ matches_mb, fail);
+
+ free (matches_mb);
+ free (expect_mb);
+ if (string_mb != string)
+ free ((char *) string_mb);
+ free (pattern_mb);
+ return ret;
+}
+
+static int
+mb_tests (const char *pattern, int cflags, const char *string, int eflags,
+ char *expect, const char *matches)
+{
+ int ret = 0;
+ int i;
+ char letters[9], fail[20];
+
+ /* The tests aren't supposed to work with xdigit, since a-dA-D are
+ hex digits while \'a \'A \v{c}\v{C}\v{d}\v{D}\'e \'E are not. */
+ if (strstr (pattern, "[:xdigit:]"))
+ return 0;
+
+ /* XXX: regex ATM handles only single byte equivalence classes. */
+ if (strstr (pattern, "[[=b=]]"))
+ return 0;
+
+ for (i = 1; i < 16; ++i)
+ {
+ char *p = letters;
+ if (i & 1)
+ {
+ if (!strchr (pattern, 'a') && !strchr (string, 'a')
+ && !strchr (pattern, 'A') && !strchr (string, 'A'))
+ continue;
+ *p++ = 'a', *p++ = 'A';
+ }
+ if (i & 2)
+ {
+ if (!strchr (pattern, 'b') && !strchr (string, 'b')
+ && !strchr (pattern, 'B') && !strchr (string, 'B'))
+ continue;
+ *p++ = 'b', *p++ = 'B';
+ }
+ if (i & 4)
+ {
+ if (!strchr (pattern, 'c') && !strchr (string, 'c')
+ && !strchr (pattern, 'C') && !strchr (string, 'C'))
+ continue;
+ *p++ = 'c', *p++ = 'C';
+ }
+ if (i & 8)
+ {
+ if (!strchr (pattern, 'd') && !strchr (string, 'd')
+ && !strchr (pattern, 'D') && !strchr (string, 'D'))
+ continue;
+ *p++ = 'd', *p++ = 'D';
+ }
+ *p++ = '\0';
+ sprintf (fail, "UTF-8 %s FAIL", letters);
+ ret |= mb_test (pattern, cflags, string, eflags, expect, matches,
+ letters, fail);
+ }
+ return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+ char *line = NULL;
+ size_t line_len = 0;
+ ssize_t len;
+ FILE *f;
+ static int test_utf8 = 0;
+ static const struct option options[] =
+ {
+ {"utf8", no_argument, &test_utf8, 1},
+ {NULL, 0, NULL, 0 }
+ };
+
+ mtrace ();
+
+ while (getopt_long (argc, argv, "", options, NULL) >= 0);
+
+ if (optind + 1 != argc)
+ {
+ fprintf (stderr, "Missing test filename\n");
+ return 1;
+ }
+
+ f = fopen (argv[optind], "r");
+ if (f == NULL)
+ {
+ fprintf (stderr, "Couldn't open %s\n", argv[optind]);
+ return 1;
+ }
+
+ while ((len = getline (&line, &line_len, f)) > 0)
+ {
+ char *pattern, *flagstr, *string, *expect, *matches, *p;
+ int cflags = REG_EXTENDED, eflags = 0, try_bre_ere = 0;
+
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+
+ /* Skip comments and empty lines. */
+ if (*line == '#' || *line == '\0')
+ continue;
+
+ puts (line);
+ fflush (stdout);
+
+ pattern = strtok (line, "\t");
+ if (pattern == NULL)
+ continue;
+
+ if (strcmp (pattern, "\"\"") == 0)
+ pattern += 2;
+
+ flagstr = strtok (NULL, "\t");
+ if (flagstr == NULL)
+ continue;
+
+ string = strtok (NULL, "\t");
+ if (string == NULL)
+ continue;
+
+ if (strcmp (string, "\"\"") == 0)
+ string += 2;
+
+ for (p = flagstr; *p; ++p)
+ switch (*p)
+ {
+ case '-':
+ break;
+ case 'b':
+ cflags &= ~REG_EXTENDED;
+ break;
+ case '&':
+ try_bre_ere = 1;
+ break;
+ case 'C':
+ eflags = -1;
+ break;
+ case 'i':
+ cflags |= REG_ICASE;
+ break;
+ case 's':
+ cflags |= REG_NOSUB;
+ break;
+ case 'n':
+ cflags |= REG_NEWLINE;
+ break;
+ case '^':
+ eflags |= REG_NOTBOL;
+ break;
+ case '$':
+ eflags |= REG_NOTEOL;
+ break;
+ case 'm':
+ case 'p':
+ case '#':
+ /* Not supported. */
+ flagstr = NULL;
+ break;
+ }
+
+ if (flagstr == NULL)
+ continue;
+
+ replace_special_chars (pattern);
+ glibc_re_syntax (pattern);
+ if (eflags != -1)
+ replace_special_chars (string);
+
+ expect = strtok (NULL, "\t");
+ matches = NULL;
+ if (expect != NULL)
+ {
+ replace_special_chars (expect);
+ matches = strtok (NULL, "\t");
+ if (matches != NULL)
+ replace_special_chars (matches);
+ }
+
+ if (setlocale (LC_ALL, "C") == NULL)
+ {
+ puts ("setlocale C failed");
+ ret = 1;
+ }
+ if (test (pattern, cflags, string, eflags, expect, matches, "FAIL")
+ || (try_bre_ere
+ && test (pattern, cflags & ~REG_EXTENDED, string, eflags,
+ expect, matches, "FAIL")))
+ ret = 1;
+ else if (test_utf8)
+ {
+ if (setlocale (LC_ALL, "cs_CZ.UTF-8") == NULL)
+ {
+ puts ("setlocale cs_CZ.UTF-8 failed");
+ ret = 1;
+ }
+ else if (test (pattern, cflags, string, eflags, expect, matches,
+ "UTF-8 FAIL")
+ || (try_bre_ere
+ && test (pattern, cflags & ~REG_EXTENDED, string,
+ eflags, expect, matches, "UTF-8 FAIL")))
+ ret = 1;
+ else if (mb_tests (pattern, cflags, string, eflags, expect, matches)
+ || (try_bre_ere
+ && mb_tests (pattern, cflags & ~REG_EXTENDED, string,
+ eflags, expect, matches)))
+ ret = 1;
+ }
+ }
+
+ free (line);
+ fclose (f);
+ return ret;
+}
diff --git a/libc/posix/tst-spawn.c b/libc/posix/tst-spawn.c
new file mode 100644
index 000000000..745f64d3b
--- /dev/null
+++ b/libc/posix/tst-spawn.c
@@ -0,0 +1,273 @@
+/* Tests for spawn.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wait.h>
+#include <sys/param.h>
+
+
+/* Nonzero if the program gets called via `exec'. */
+static int restart;
+
+
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+
+/* Prototype for our test function. */
+extern void do_prepare (int argc, char *argv[]);
+extern int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+#define PREPARE do_prepare
+
+#include "../test-skeleton.c"
+
+
+/* Name of the temporary files. */
+static char *name1;
+static char *name2;
+static char *name3;
+
+/* The contents of our files. */
+static const char fd1string[] = "This file should get closed";
+static const char fd2string[] = "This file should stay opened";
+static const char fd3string[] = "This file will be opened";
+
+
+/* We have a preparation function. */
+void
+do_prepare (int argc, char *argv[])
+{
+ char name_len;
+
+ name_len = strlen (test_dir);
+ name1 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX"));
+ mempcpy (mempcpy (name1, test_dir, name_len),
+ "/spawnXXXXXX", sizeof ("/spawnXXXXXX"));
+ add_temp_file (name1);
+
+ name2 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX"));
+ mempcpy (mempcpy (name2, test_dir, name_len),
+ "/spawnXXXXXX", sizeof ("/spawnXXXXXX"));
+ add_temp_file (name2);
+
+ name3 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX"));
+ mempcpy (mempcpy (name3, test_dir, name_len),
+ "/spawnXXXXXX", sizeof ("/spawnXXXXXX"));
+ add_temp_file (name3);
+}
+
+
+static int
+handle_restart (const char *fd1s, const char *fd2s, const char *fd3s,
+ const char *fd4s, const char *name)
+{
+ char buf[100];
+ int fd1;
+ int fd2;
+ int fd3;
+ int fd4;
+
+ /* First get the descriptors. */
+ fd1 = atol (fd1s);
+ fd2 = atol (fd2s);
+ fd3 = atol (fd3s);
+ fd4 = atol (fd4s);
+
+ /* Sanity check. */
+ if (fd1 == fd2)
+ error (EXIT_FAILURE, 0, "value of fd1 and fd2 is the same");
+ if (fd1 == fd3)
+ error (EXIT_FAILURE, 0, "value of fd1 and fd3 is the same");
+ if (fd1 == fd4)
+ error (EXIT_FAILURE, 0, "value of fd1 and fd4 is the same");
+ if (fd2 == fd3)
+ error (EXIT_FAILURE, 0, "value of fd2 and fd3 is the same");
+ if (fd2 == fd4)
+ error (EXIT_FAILURE, 0, "value of fd2 and fd4 is the same");
+ if (fd3 == fd4)
+ error (EXIT_FAILURE, 0, "value of fd3 and fd4 is the same");
+
+ /* First the easy part: read from the file descriptor which is
+ supposed to be open. */
+ if (lseek (fd2, 0, SEEK_CUR) != strlen (fd2string))
+ error (EXIT_FAILURE, errno, "file 2 not in right position");
+ /* The duped descriptor must have the same position. */
+ if (lseek (fd4, 0, SEEK_CUR) != strlen (fd2string))
+ error (EXIT_FAILURE, errno, "file 4 not in right position");
+ if (lseek (fd2, 0, SEEK_SET) != 0)
+ error (EXIT_FAILURE, 0, "cannot reset position in file 2");
+ if (lseek (fd4, 0, SEEK_CUR) != 0)
+ error (EXIT_FAILURE, errno, "file 4 not set back, too");
+ if (read (fd2, buf, sizeof buf) != strlen (fd2string))
+ error (EXIT_FAILURE, 0, "cannot read file 2");
+ if (memcmp (fd2string, buf, strlen (fd2string)) != 0)
+ error (EXIT_FAILURE, 0, "file 2 does not match");
+
+ /* Now read from the third file. */
+ if (read (fd3, buf, sizeof buf) != strlen (fd3string))
+ error (EXIT_FAILURE, 0, "cannot read file 3");
+ if (memcmp (fd3string, buf, strlen (fd3string)) != 0)
+ error (EXIT_FAILURE, 0, "file 3 does not match");
+ /* Try to write to the file. This should not be allowed. */
+ if (write (fd3, "boo!", 4) != -1 || errno != EBADF)
+ error (EXIT_FAILURE, 0, "file 3 is writable");
+
+ /* Now try to read the first file. First make sure it is not opened. */
+ if (lseek (fd1, 0, SEEK_CUR) != (off_t) -1 || errno != EBADF)
+ error (EXIT_FAILURE, 0, "file 1 (%d) is not closed", fd1);
+
+ /* Now open the file and read it. */
+ fd1 = open (name, O_RDONLY);
+ if (fd1 == -1)
+ error (EXIT_FAILURE, errno,
+ "cannot open first file \"%s\" for verification", name);
+
+ if (read (fd1, buf, sizeof buf) != strlen (fd1string))
+ error (EXIT_FAILURE, errno, "cannot read file 1");
+ if (memcmp (fd1string, buf, strlen (fd1string)) != 0)
+ error (EXIT_FAILURE, 0, "file 1 does not match");
+
+ return 0;
+}
+
+
+int
+do_test (int argc, char *argv[])
+{
+ pid_t pid;
+ int fd1;
+ int fd2;
+ int fd3;
+ int fd4;
+ int status;
+ posix_spawn_file_actions_t actions;
+ char fd1name[18];
+ char fd2name[18];
+ char fd3name[18];
+ char fd4name[18];
+ char *spargv[12];
+
+ /* We must have
+ - four parameters left of called initially
+ + path for ld.so
+ + "--library-path"
+ + the library path
+ + the application name
+ - five parameters left if called through re-execution
+ + file descriptor number which is supposed to be closed
+ + the open file descriptor
+ + the newly opened file descriptor
+ + thhe duped second descriptor
+ + the name of the closed descriptor
+ */
+ if (argc != (restart ? 6 : 5))
+ error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc);
+
+ if (restart)
+ return handle_restart (argv[1], argv[2], argv[3], argv[4], argv[5]);
+
+ /* Prepare the test. We are creating two files: one which file descriptor
+ will be marked with FD_CLOEXEC, another which is not. */
+
+ /* Open our test files. */
+ fd1 = mkstemp (name1);
+ if (fd1 == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name1);
+ fd2 = mkstemp (name2);
+ if (fd2 == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name2);
+ fd3 = mkstemp (name3);
+ if (fd3 == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name3);
+
+ /* Write something in the files. */
+ if (write (fd1, fd1string, strlen (fd1string)) != strlen (fd1string))
+ error (EXIT_FAILURE, errno, "cannot write to first file");
+ if (write (fd2, fd2string, strlen (fd2string)) != strlen (fd2string))
+ error (EXIT_FAILURE, errno, "cannot write to second file");
+ if (write (fd3, fd3string, strlen (fd3string)) != strlen (fd3string))
+ error (EXIT_FAILURE, errno, "cannot write to third file");
+
+ /* Close the third file. It'll be opened by `spawn'. */
+ close (fd3);
+
+ /* Tell `spawn' what to do. */
+ if (posix_spawn_file_actions_init (&actions) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn_file_actions_init");
+ /* Close `fd1'. */
+ if (posix_spawn_file_actions_addclose (&actions, fd1) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose");
+ /* We want to open the third file. */
+ if (posix_spawn_file_actions_addopen (&actions, fd3, name3,
+ O_RDONLY, 0666) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen");
+ /* We dup the second descriptor. */
+ fd4 = MAX (2, MAX (fd1, MAX (fd2, fd3))) + 1;
+ if (posix_spawn_file_actions_adddup2 (&actions, fd2, fd4) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn_file_actions_adddup2");
+
+ /* Now spawn the process. */
+ snprintf (fd1name, sizeof fd1name, "%d", fd1);
+ snprintf (fd2name, sizeof fd2name, "%d", fd2);
+ snprintf (fd3name, sizeof fd3name, "%d", fd3);
+ snprintf (fd4name, sizeof fd4name, "%d", fd4);
+
+ spargv[0] = argv[1];
+ spargv[1] = argv[2];
+ spargv[2] = argv[3];
+ spargv[3] = argv[4];
+ spargv[4] = (char *) "--direct";
+ spargv[5] = (char *) "--restart";
+ spargv[6] = fd1name;
+ spargv[7] = fd2name;
+ spargv[8] = fd3name;
+ spargv[9] = fd4name;
+ spargv[10] = name1;
+ spargv[11] = NULL;
+
+ if (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn");
+
+ /* Cleanup. */
+ if (posix_spawn_file_actions_destroy (&actions) != 0)
+ error (EXIT_FAILURE, errno, "posix_spawn_file_actions_destroy");
+
+ /* Wait for the child. */
+ if (waitpid (pid, &status, 0) != pid)
+ error (EXIT_FAILURE, errno, "wrong child");
+
+ if (WTERMSIG (status) != 0)
+ error (EXIT_FAILURE, 0, "Child terminated incorrectly");
+ status = WEXITSTATUS (status);
+
+ /* Remove the test files. */
+ unlink (name1);
+ unlink (name2);
+ unlink (name3);
+
+ return status;
+}
diff --git a/libc/posix/tst-sysconf.c b/libc/posix/tst-sysconf.c
new file mode 100644
index 000000000..e9ff06a8d
--- /dev/null
+++ b/libc/posix/tst-sysconf.c
@@ -0,0 +1,114 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static struct
+{
+ long int _P_val;
+ const char *name;
+ int _SC_val;
+ bool positive;
+ bool posix2;
+} posix_options[] =
+ {
+#define N_(name, pos) { _POSIX_##name, #name, _SC_##name, pos, false }
+#define NP(name) N_ (name, true)
+#define N(name) N_ (name, false)
+#define N2(name) { _POSIX2_##name, #name, _SC_2_##name, false, true }
+ N (ADVISORY_INFO),
+ N (ASYNCHRONOUS_IO),
+ N (BARRIERS),
+ N (CLOCK_SELECTION),
+ N (CPUTIME),
+ N (FSYNC),
+ N (IPV6),
+ NP (JOB_CONTROL),
+ N (MAPPED_FILES),
+ N (MEMLOCK),
+ N (MEMLOCK_RANGE),
+ N (MEMORY_PROTECTION),
+ N (MESSAGE_PASSING),
+ N (MONOTONIC_CLOCK),
+ N (PRIORITIZED_IO),
+ N (PRIORITY_SCHEDULING),
+ N (RAW_SOCKETS),
+ N (READER_WRITER_LOCKS),
+ N (REALTIME_SIGNALS),
+ NP (REGEXP),
+ NP (SAVED_IDS),
+ N (SEMAPHORES),
+ N (SHARED_MEMORY_OBJECTS),
+ NP (SHELL),
+ N (SPAWN),
+ N (SPIN_LOCKS),
+ N (SPORADIC_SERVER),
+ N (SYNCHRONIZED_IO),
+ N (THREAD_ATTR_STACKADDR),
+ N (THREAD_ATTR_STACKSIZE),
+ N (THREAD_CPUTIME),
+ N (THREAD_PRIO_INHERIT),
+ N (THREAD_PRIO_PROTECT),
+ N (THREAD_PRIORITY_SCHEDULING),
+ N (THREAD_PROCESS_SHARED),
+ N (THREAD_SAFE_FUNCTIONS),
+ N (THREAD_SPORADIC_SERVER),
+ N (THREADS),
+ N (TIMEOUTS),
+ N (TIMERS),
+ N (TRACE),
+ N (TRACE_EVENT_FILTER),
+ N (TRACE_INHERIT),
+ N (TRACE_LOG),
+ N (TYPED_MEMORY_OBJECTS),
+ N2 (C_BIND),
+ N2 (C_DEV),
+ N2 (CHAR_TERM)
+ };
+#define nposix_options (sizeof (posix_options) / sizeof (posix_options[0]))
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ for (int i = 0; i < nposix_options; ++i)
+ {
+ long int scret = sysconf (posix_options[i]._SC_val);
+
+ if (scret == 0)
+ {
+ printf ("sysconf(_SC_%s%s) returned zero\n",
+ posix_options[i].posix2 ? "2_" : "", posix_options[i].name);
+ result = 1;
+ }
+ if (posix_options[i]._P_val != 0 && posix_options[i]._P_val != scret)
+ {
+ printf ("sysconf(_SC_%s%s) = %ld does not match _POSIX%s_%s = %ld\n",
+ posix_options[i].posix2 ? "2_" : "", posix_options[i].name,
+ scret,
+ posix_options[i].posix2 ? "2" : "", posix_options[i].name,
+ posix_options[i]._P_val);
+ result = 1;
+ }
+ else if (posix_options[i].positive && scret < 0)
+ {
+ printf ("sysconf(_SC_%s%s) must be > 0\n",
+ posix_options[i].posix2 ? "2_" : "", posix_options[i].name);
+ result = 1;
+ }
+
+#define STDVER 200112L
+ if (scret > 0 && scret != STDVER && !posix_options[i].positive)
+ {
+ printf ("sysconf(_SC_%s%s) must be %ldL\n",
+ posix_options[i].posix2 ? "2_" : "", posix_options[i].name,
+ STDVER);
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-truncate.c b/libc/posix/tst-truncate.c
new file mode 100644
index 000000000..d78630640
--- /dev/null
+++ b/libc/posix/tst-truncate.c
@@ -0,0 +1,133 @@
+/* Tests for ftruncate and truncate.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+/* Allow testing of the 64-bit versions as well. */
+#ifndef TRUNCATE
+# define TRUNCATE truncate
+# define FTRUNCATE ftruncate
+#endif
+
+#define STRINGIFY(s) STRINGIFY2 (s)
+#define STRINGIFY2(s) #s
+
+/* Prototype for our test function. */
+extern void do_prepare (int argc, char *argv[]);
+extern int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+#define PREPARE do_prepare
+
+/* We might need a bit longer timeout. */
+#define TIMEOUT 20 /* sec */
+
+/* This defines the `main' function and some more. */
+#include <test-skeleton.c>
+
+/* These are for the temporary file we generate. */
+char *name;
+int fd;
+
+void
+do_prepare (int argc, char *argv[])
+{
+ char name_len;
+
+#define FNAME FNAME2(TRUNCATE)
+#define FNAME2(s) "/" STRINGIFY(s) "XXXXXX"
+
+ name_len = strlen (test_dir);
+ name = malloc (name_len + sizeof (FNAME));
+ mempcpy (mempcpy (name, test_dir, name_len), FNAME, sizeof (FNAME));
+ add_temp_file (name);
+
+ /* Open our test file. */
+ fd = mkstemp (name);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
+}
+
+
+int
+do_test (int argc, char *argv[])
+{
+ struct stat st;
+ char buf[1000];
+
+ memset (buf, '\0', sizeof (buf));
+
+ if (write (fd, buf, sizeof (buf)) != sizeof (buf))
+ error (EXIT_FAILURE, errno, "during write");
+
+ if (fstat (fd, &st) < 0 || st.st_size != sizeof (buf))
+ error (EXIT_FAILURE, 0, "initial size wrong");
+
+
+ if (FTRUNCATE (fd, 800) < 0)
+ error (EXIT_FAILURE, errno, "size reduction with %s failed",
+ STRINGIFY (FTRUNCATE));
+
+ if (fstat (fd, &st) < 0 || st.st_size != 800)
+ error (EXIT_FAILURE, 0, "size after reduction with %s incorrect",
+ STRINGIFY (FTRUNCATE));
+
+ /* The following test covers more than POSIX. POSIX does not require
+ that ftruncate() can increase the file size. But we are testing
+ Unix systems. */
+ if (FTRUNCATE (fd, 1200) < 0)
+ error (EXIT_FAILURE, errno, "size increase with %s failed",
+ STRINGIFY (FTRUNCATE));
+
+ if (fstat (fd, &st) < 0 || st.st_size != 1200)
+ error (EXIT_FAILURE, 0, "size after increase with %s incorrect",
+ STRINGIFY (FTRUNCATE));
+
+
+ if (TRUNCATE (name, 800) < 0)
+ error (EXIT_FAILURE, errno, "size reduction with %s failed",
+ STRINGIFY (TRUNCATE));
+
+ if (fstat (fd, &st) < 0 || st.st_size != 800)
+ error (EXIT_FAILURE, 0, "size after reduction with %s incorrect",
+ STRINGIFY (TRUNCATE));
+
+ /* The following test covers more than POSIX. POSIX does not require
+ that truncate() can increase the file size. But we are testing
+ Unix systems. */
+ if (TRUNCATE (name, 1200) < 0)
+ error (EXIT_FAILURE, errno, "size increase with %s failed",
+ STRINGIFY (TRUNCATE));
+
+ if (fstat (fd, &st) < 0 || st.st_size != 1200)
+ error (EXIT_FAILURE, 0, "size after increase with %s incorrect",
+ STRINGIFY (TRUNCATE));
+
+
+ close (fd);
+ unlink (name);
+
+ return 0;
+}
diff --git a/libc/posix/tst-truncate64.c b/libc/posix/tst-truncate64.c
new file mode 100644
index 000000000..4aacfbb1b
--- /dev/null
+++ b/libc/posix/tst-truncate64.c
@@ -0,0 +1,24 @@
+/* Tests for ftruncate64 and truncate64.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define TRUNCATE truncate64
+#define FTRUNCATE ftruncate64
+
+#include "tst-truncate.c"
diff --git a/libc/posix/tst-vfork1.c b/libc/posix/tst-vfork1.c
new file mode 100644
index 000000000..1f36f1ff2
--- /dev/null
+++ b/libc/posix/tst-vfork1.c
@@ -0,0 +1,150 @@
+/* Test for vfork functions.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* This test relies on non-POSIX functionality since the child
+ processes call write and getpid. */
+static int
+do_test (void)
+{
+ int result = 0;
+ int fd[2];
+
+ if (pipe (fd) == -1)
+ {
+ puts ("pipe failed");
+ return 1;
+ }
+
+ /* First vfork() without previous getpid(). */
+ pid_t p1;
+ if ((p1 = vfork ()) == 0)
+ {
+ pid_t p = getpid ();
+ _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+ }
+ else if (p1 == -1)
+ {
+ puts ("1st vfork failed");
+ result = 1;
+ }
+
+ pid_t p2 = 0;
+ if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+ {
+ puts ("1st read failed");
+ result = 1;
+ }
+ int r;
+ if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+ {
+ puts ("1st waitpid failed");
+ result = 1;
+ }
+ else if (r != 0)
+ {
+ puts ("write in 1st child failed");
+ result = 1;
+ }
+
+ /* Main process' ID. */
+ pid_t p0 = getpid ();
+
+ /* vfork() again, but after a getpid() in the main process. */
+ pid_t p3;
+ if ((p3 = vfork ()) == 0)
+ {
+ pid_t p = getpid ();
+ _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+ }
+ else if (p1 == -1)
+ {
+ puts ("2nd vfork failed");
+ result = 1;
+ }
+
+ pid_t p4;
+ if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+ {
+ puts ("2nd read failed");
+ result = 1;
+ }
+ if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+ {
+ puts ("2nd waitpid failed");
+ result = 1;
+ }
+ else if (r != 0)
+ {
+ puts ("write in 2nd child failed");
+ result = 1;
+ }
+
+ /* And getpid in the main process again. */
+ pid_t p5 = getpid ();
+
+ /* Analysis of the results. */
+ if (p0 != p5)
+ {
+ printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+ result = 1;
+ }
+
+ if (p0 == p1)
+ {
+ printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+ result = 1;
+ }
+
+ if (p1 != p2)
+ {
+ printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+ result = 1;
+ }
+
+ if (p0 == p3)
+ {
+ printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+ result = 1;
+ }
+
+ if (p3 != p4)
+ {
+ printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+ result = 1;
+ }
+
+ close (fd[0]);
+ close (fd[1]);
+
+ if (result == 0)
+ puts ("All OK");
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-vfork2.c b/libc/posix/tst-vfork2.c
new file mode 100644
index 000000000..1d096e14a
--- /dev/null
+++ b/libc/posix/tst-vfork2.c
@@ -0,0 +1,199 @@
+/* Test for vfork functions.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int raise_fail;
+
+static void
+alrm (int sig)
+{
+ if (raise (SIGUSR1) < 0)
+ raise_fail = 1;
+}
+
+/* This test relies on non-POSIX functionality since the child
+ processes call write, nanosleep and getpid. */
+static int
+do_test (void)
+{
+ int result = 0;
+ int fd[2];
+
+ signal (SIGUSR1, SIG_IGN);
+
+ struct sigaction sa;
+ sa.sa_handler = alrm;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (sigaction (SIGALRM, &sa, NULL) < 0)
+ {
+ puts ("couldn't set up SIGALRM handler");
+ return 1;
+ }
+
+ if (pipe (fd) == -1)
+ {
+ puts ("pipe failed");
+ return 1;
+ }
+
+ struct itimerval it;
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = 200 * 1000;
+ it.it_interval = it.it_value;
+ if (setitimer (ITIMER_REAL, &it, NULL) < 0)
+ {
+ puts ("couldn't set up timer");
+ return 1;
+ }
+
+ /* First vfork() without previous getpid(). */
+ pid_t p1;
+ if ((p1 = vfork ()) == 0)
+ {
+ pid_t p = getpid ();
+
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+ _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+ }
+ else if (p1 == -1)
+ {
+ puts ("1st vfork failed");
+ result = 1;
+ }
+
+ memset (&it, 0, sizeof (it));
+ setitimer (ITIMER_REAL, &it, NULL);
+
+ pid_t p2 = 0;
+ if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+ {
+ puts ("1st read failed");
+ result = 1;
+ }
+ int r;
+ if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+ {
+ puts ("1st waitpid failed");
+ result = 1;
+ }
+ else if (r != 0)
+ {
+ puts ("write in 1st child failed");
+ result = 1;
+ }
+
+ /* Main process' ID. */
+ pid_t p0 = getpid ();
+
+ /* vfork() again, but after a getpid() in the main process. */
+ pid_t p3;
+ if ((p3 = vfork ()) == 0)
+ {
+ pid_t p = getpid ();
+ _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+ }
+ else if (p1 == -1)
+ {
+ puts ("2nd vfork failed");
+ result = 1;
+ }
+
+ pid_t p4;
+ if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+ {
+ puts ("2nd read failed");
+ result = 1;
+ }
+ if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+ {
+ puts ("2nd waitpid failed");
+ result = 1;
+ }
+ else if (r != 0)
+ {
+ puts ("write in 2nd child failed");
+ result = 1;
+ }
+
+ /* And getpid in the main process again. */
+ pid_t p5 = getpid ();
+
+ /* Analysis of the results. */
+ if (p0 != p5)
+ {
+ printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+ result = 1;
+ }
+
+ if (p0 == p1)
+ {
+ printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+ result = 1;
+ }
+
+ if (p1 != p2)
+ {
+ printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+ result = 1;
+ }
+
+ if (p0 == p3)
+ {
+ printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+ result = 1;
+ }
+
+ if (p3 != p4)
+ {
+ printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+ result = 1;
+ }
+
+ close (fd[0]);
+ close (fd[1]);
+
+ if (raise_fail)
+ {
+ puts ("raise failed");
+ result = 1;
+ }
+
+ if (result == 0)
+ puts ("All OK");
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/posix/tst-waitid.c b/libc/posix/tst-waitid.c
new file mode 100644
index 000000000..d810922f0
--- /dev/null
+++ b/libc/posix/tst-waitid.c
@@ -0,0 +1,514 @@
+/* Tests for waitid.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define TIMEOUT 15
+
+static void
+test_child (void)
+{
+ /* Wait a second to be sure the parent set his variables before we
+ produce a SIGCHLD. */
+ sleep (1);
+
+ /* First thing, we stop ourselves. */
+ raise (SIGSTOP);
+
+ /* Hey, we got continued! */
+ while (1)
+ pause ();
+}
+
+#ifndef WEXITED
+# define WEXITED 0
+# define WCONTINUED 0
+# define WSTOPPED WUNTRACED
+#endif
+
+static sig_atomic_t expecting_sigchld, spurious_sigchld;
+#ifdef SA_SIGINFO
+static siginfo_t sigchld_info;
+
+static void
+sigchld (int signo, siginfo_t *info, void *ctx)
+{
+ if (signo != SIGCHLD)
+ {
+ printf ("SIGCHLD handler got signal %d instead!\n", signo);
+ _exit (EXIT_FAILURE);
+ }
+
+ if (! expecting_sigchld)
+ {
+ spurious_sigchld = 1;
+ printf ("spurious SIGCHLD: signo %d code %d status %d pid %d\n",
+ info->si_signo, info->si_code, info->si_status, info->si_pid);
+ }
+ else
+ {
+ sigchld_info = *info;
+ expecting_sigchld = 0;
+ }
+}
+
+static void
+check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
+{
+ if (expecting_sigchld)
+ {
+ printf ("missing SIGCHLD on %s\n", phase);
+ *ok = EXIT_FAILURE;
+ expecting_sigchld = 0;
+ return;
+ }
+
+ if (sigchld_info.si_signo != SIGCHLD)
+ {
+ printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
+ *ok = EXIT_FAILURE;
+ }
+ if (sigchld_info.si_code != code)
+ {
+ printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
+ *ok = EXIT_FAILURE;
+ }
+ if (sigchld_info.si_status != status)
+ {
+ printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
+ *ok = EXIT_FAILURE;
+ }
+ if (sigchld_info.si_pid != pid)
+ {
+ printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
+ *ok = EXIT_FAILURE;
+ }
+}
+# define CHECK_SIGCHLD(phase, code_check, status_check) \
+ check_sigchld ((phase), &status, (code_check), (status_check), pid)
+#else
+# define CHECK_SIGCHLD(phase, code, status) ((void) 0)
+#endif
+
+static int
+do_test (int argc, char *argv[])
+{
+#ifdef SA_SIGINFO
+ struct sigaction sa;
+ sa.sa_flags = SA_SIGINFO|SA_RESTART;
+ sa.sa_sigaction = &sigchld;
+ if (sigemptyset (&sa.sa_mask) < 0 || sigaction (SIGCHLD, &sa, NULL) < 0)
+ {
+ printf ("setting SIGCHLD handler: %m\n");
+ return EXIT_FAILURE;
+ }
+#endif
+
+ expecting_sigchld = 1;
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork: %m\n");
+ return EXIT_FAILURE;
+ }
+ else if (pid == 0)
+ {
+ test_child ();
+ _exit (127);
+ }
+
+ int status = EXIT_SUCCESS;
+#define RETURN(ok) \
+ do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
+
+ /* Give the child a chance to stop. */
+ sleep (3);
+
+ CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
+
+ /* Now try a wait that should not succeed. */
+ siginfo_t info;
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ int fail = waitid (P_PID, pid, &info, WEXITED|WCONTINUED|WNOHANG);
+ switch (fail)
+ {
+ default:
+ printf ("waitid returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WNOHANG on stopped: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo == 0)
+ break;
+ if (info.si_signo == SIGCHLD)
+ printf ("waitid WNOHANG on stopped status %d\n", info.si_status);
+ else
+ printf ("waitid WNOHANG on stopped signal %d\n", info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+
+ /* Next the wait that should succeed right away. */
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ info.si_pid = -1;
+ info.si_status = -1;
+ fail = waitid (P_PID, pid, &info, WSTOPPED|WNOHANG);
+ switch (fail)
+ {
+ default:
+ printf ("waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WSTOPPED|WNOHANG on stopped: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo != SIGCHLD)
+ {
+ printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
+ info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_code != CLD_STOPPED)
+ {
+ printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
+ info.si_code);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_status != SIGSTOP)
+ {
+ printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
+ info.si_status);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_pid != pid)
+ {
+ printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
+ info.si_pid, pid);
+ RETURN (EXIT_FAILURE);
+ }
+ }
+
+ expecting_sigchld = WCONTINUED != 0;
+
+ if (kill (pid, SIGCONT) != 0)
+ {
+ printf ("kill (%d, SIGCONT): %m\n", pid);
+ RETURN (EXIT_FAILURE);
+ }
+
+ /* Wait for the child to have continued. */
+ sleep (2);
+
+#if WCONTINUED != 0
+ if (expecting_sigchld)
+ {
+ printf ("no SIGCHLD seen for SIGCONT (optional)\n");
+ expecting_sigchld = 0;
+ }
+ else
+ CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
+
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ info.si_pid = -1;
+ info.si_status = -1;
+ fail = waitid (P_PID, pid, &info, WCONTINUED|WNOWAIT);
+ switch (fail)
+ {
+ default:
+ printf ("waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WCONTINUED|WNOWAIT on continued: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo != SIGCHLD)
+ {
+ printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
+ info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_code != CLD_CONTINUED)
+ {
+ printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
+ info.si_code);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_status != SIGCONT)
+ {
+ printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
+ info.si_status);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_pid != pid)
+ {
+ printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
+ info.si_pid, pid);
+ RETURN (EXIT_FAILURE);
+ }
+ }
+
+ /* That should leave the CLD_CONTINUED state waiting to be seen again. */
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ info.si_pid = -1;
+ info.si_status = -1;
+ fail = waitid (P_PID, pid, &info, WCONTINUED);
+ switch (fail)
+ {
+ default:
+ printf ("waitid WCONTINUED returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WCONTINUED on continued: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo != SIGCHLD)
+ {
+ printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_code != CLD_CONTINUED)
+ {
+ printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_status != SIGCONT)
+ {
+ printf ("waitid WCONTINUED on continued status %d\n",
+ info.si_status);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_pid != pid)
+ {
+ printf ("waitid WCONTINUED on continued pid %d != %d\n",
+ info.si_pid, pid);
+ RETURN (EXIT_FAILURE);
+ }
+ }
+
+ /* Now try a wait that should not succeed. */
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ fail = waitid (P_PID, pid, &info, WCONTINUED|WNOHANG);
+ switch (fail)
+ {
+ default:
+ printf ("waitid returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WCONTINUED|WNOHANG on waited continued: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo == 0)
+ break;
+ if (info.si_signo == SIGCHLD)
+ printf ("waitid WCONTINUED|WNOHANG on waited continued status %d\n",
+ info.si_status);
+ else
+ printf ("waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
+ info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+
+ /* Now stop him again and test waitpid with WCONTINUED. */
+ expecting_sigchld = 1;
+ if (kill (pid, SIGSTOP) != 0)
+ {
+ printf ("kill (%d, SIGSTOP): %m\n", pid);
+ RETURN (EXIT_FAILURE);
+ }
+ pid_t wpid = waitpid (pid, &fail, WUNTRACED);
+ if (wpid < 0)
+ {
+ printf ("waitpid WUNTRACED on stopped: %m\n");
+ RETURN (EXIT_FAILURE);
+ }
+ else if (wpid != pid)
+ {
+ printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
+ wpid, pid, fail);
+ RETURN (EXIT_FAILURE);
+ }
+ else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
+ || WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
+ {
+ printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
+ RETURN (EXIT_FAILURE);
+ }
+ CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
+
+ expecting_sigchld = 1;
+ if (kill (pid, SIGCONT) != 0)
+ {
+ printf ("kill (%d, SIGCONT): %m\n", pid);
+ RETURN (EXIT_FAILURE);
+ }
+
+ /* Wait for the child to have continued. */
+ sleep (2);
+
+ if (expecting_sigchld)
+ {
+ printf ("no SIGCHLD seen for SIGCONT (optional)\n");
+ expecting_sigchld = 0;
+ }
+ else
+ CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
+
+ wpid = waitpid (pid, &fail, WCONTINUED);
+ if (wpid < 0)
+ {
+ if (errno == EINVAL)
+ printf ("waitpid does not support WCONTINUED\n");
+ else
+ {
+ printf ("waitpid WCONTINUED on continued: %m\n");
+ RETURN (EXIT_FAILURE);
+ }
+ }
+ else if (wpid != pid)
+ {
+ printf ("\
+waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
+ wpid, pid, fail);
+ RETURN (EXIT_FAILURE);
+ }
+ else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
+ || !WIFCONTINUED (fail))
+ {
+ printf ("waitpid WCONTINUED on continued: status %x\n", fail);
+ RETURN (EXIT_FAILURE);
+ }
+#endif
+
+ expecting_sigchld = 1;
+
+ /* Die, child, die! */
+ if (kill (pid, SIGKILL) != 0)
+ {
+ printf ("kill (%d, SIGKILL): %m\n", pid);
+ RETURN (EXIT_FAILURE);
+ }
+
+#ifdef WNOWAIT
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ info.si_pid = -1;
+ info.si_status = -1;
+ fail = waitid (P_PID, pid, &info, WEXITED|WNOWAIT);
+ switch (fail)
+ {
+ default:
+ printf ("waitid WNOWAIT returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WNOWAIT on killed: %m\n");
+ RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
+ case 0:
+ if (info.si_signo != SIGCHLD)
+ {
+ printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_code != CLD_KILLED)
+ {
+ printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_status != SIGKILL)
+ {
+ printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_pid != pid)
+ {
+ printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
+ RETURN (EXIT_FAILURE);
+ }
+ }
+#else
+ /* Allow enough time to be sure the child died; we didn't synchronize. */
+ sleep (2);
+#endif
+
+ CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
+
+ info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
+ info.si_pid = -1;
+ info.si_status = -1;
+ fail = waitid (P_PID, pid, &info, WEXITED|WNOHANG);
+ switch (fail)
+ {
+ default:
+ printf ("waitid WNOHANG returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ case -1:
+ printf ("waitid WNOHANG on killed: %m\n");
+ RETURN (EXIT_FAILURE);
+ case 0:
+ if (info.si_signo != SIGCHLD)
+ {
+ printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_code != CLD_KILLED)
+ {
+ printf ("waitid WNOHANG on killed code %d\n", info.si_code);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_status != SIGKILL)
+ {
+ printf ("waitid WNOHANG on killed status %d\n", info.si_status);
+ RETURN (EXIT_FAILURE);
+ }
+ if (info.si_pid != pid)
+ {
+ printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
+ RETURN (EXIT_FAILURE);
+ }
+ }
+
+ fail = waitid (P_PID, pid, &info, WEXITED);
+ if (fail == -1)
+ {
+ if (errno != ECHILD)
+ {
+ printf ("waitid WEXITED on killed: %m\n");
+ RETURN (EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ printf ("waitid WEXITED returned bogus value %d\n", fail);
+ RETURN (EXIT_FAILURE);
+ }
+
+#undef RETURN
+ out:
+ if (spurious_sigchld)
+ status = EXIT_FAILURE;
+ signal (SIGCHLD, SIG_IGN);
+ kill (pid, SIGKILL); /* Make sure it's dead if we bailed early. */
+ return status;
+}
+
+#include "../test-skeleton.c"
diff --git a/libc/posix/tstgetopt.c b/libc/posix/tstgetopt.c
new file mode 100644
index 000000000..97ae2ef25
--- /dev/null
+++ b/libc/posix/tstgetopt.c
@@ -0,0 +1,76 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+main (int argc, char **argv)
+{
+ static const struct option options[] =
+ {
+ {"required", required_argument, NULL, 'r'},
+ {"optional", optional_argument, NULL, 'o'},
+ {"none", no_argument, NULL, 'n'},
+ {"color", no_argument, NULL, 'C'},
+ {"colour", no_argument, NULL, 'C'},
+ {NULL, 0, NULL, 0 }
+ };
+
+ int aflag = 0;
+ int bflag = 0;
+ char *cvalue = NULL;
+ int Cflag = 0;
+ int nflag = 0;
+ int index;
+ int c;
+ int result = 0;
+
+ while ((c = getopt_long (argc, argv, "abc:", options, NULL)) >= 0)
+ switch (c)
+ {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cvalue = optarg;
+ break;
+ case 'C':
+ ++Cflag;
+ break;
+ case '?':
+ fputs ("Unknown option.\n", stderr);
+ return 1;
+ default:
+ fprintf (stderr, "This should never happen!\n");
+ return 1;
+
+ case 'r':
+ printf ("--required %s\n", optarg);
+ result |= strcmp (optarg, "foobar") != 0;
+ break;
+ case 'o':
+ printf ("--optional %s\n", optarg);
+ result |= optarg == NULL || strcmp (optarg, "bazbug") != 0;
+ break;
+ case 'n':
+ puts ("--none");
+ nflag = 1;
+ break;
+ }
+
+ printf ("aflag = %d, bflag = %d, cvalue = %s, Cflags = %d, nflag = %d\n",
+ aflag, bflag, cvalue, Cflag, nflag);
+
+ result |= (aflag != 1 || bflag != 1 || cvalue == NULL
+ || strcmp (cvalue, "foobar") != 0 || Cflag != 3 || nflag != 1);
+
+ for (index = optind; index < argc; index++)
+ printf ("Non-option argument %s\n", argv[index]);
+
+ result |= optind + 1 != argc || strcmp (argv[optind], "random") != 0;
+
+ return result;
+}
diff --git a/libc/posix/uname.c b/libc/posix/uname.c
new file mode 100644
index 000000000..e7c41648e
--- /dev/null
+++ b/libc/posix/uname.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 1991,92,96,97,2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+/* This file is created by the configuration process, and defines UNAME_*. */
+#include <config-name.h>
+
+/* Put information about the system in NAME. */
+int
+__uname (name)
+ struct utsname *name;
+{
+ int save;
+
+ if (name == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ save = errno;
+ if (__gethostname (name->nodename, sizeof (name->nodename)) < 0)
+ {
+ if (errno == ENOSYS)
+ {
+ /* Hostname is meaningless for this machine. */
+ name->nodename[0] = '\0';
+ __set_errno (save);
+ }
+#ifdef ENAMETOOLONG
+ else if (errno == ENAMETOOLONG)
+ /* The name was truncated. */
+ __set_errno (save);
+#endif
+ else
+ return -1;
+ }
+ strncpy (name->sysname, UNAME_SYSNAME, sizeof (name->sysname));
+ strncpy (name->release, UNAME_RELEASE, sizeof (name->release));
+ strncpy (name->version, UNAME_VERSION, sizeof (name->version));
+ strncpy (name->machine, UNAME_MACHINE, sizeof (name->machine));
+
+ return 0;
+}
+weak_alias (__uname, uname)
+libc_hidden_def (__uname)
+libc_hidden_def (uname)
diff --git a/libc/posix/unistd.h b/libc/posix/unistd.h
new file mode 100644
index 000000000..c7a52722c
--- /dev/null
+++ b/libc/posix/unistd.h
@@ -0,0 +1,1103 @@
+/* Copyright (C) 1991-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 2.10 Symbolic Constants <unistd.h>
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* These may be used to determine what facilities are present at compile time.
+ Their values can be obtained at run time from `sysconf'. */
+
+/* POSIX Standard approved as ISO/IEC 9945-1 as of December 2001. */
+#define _POSIX_VERSION 200112L
+
+/* These are not #ifdef __USE_POSIX2 because they are
+ in the theoretically application-owned namespace. */
+
+/* The utilities on GNU systems also correspond to this version. */
+#define _POSIX2_VERSION 200112L
+
+/* If defined, the implementation supports the
+ C Language Bindings Option. */
+#define _POSIX2_C_BIND 200112L
+
+/* If defined, the implementation supports the
+ C Language Development Utilities Option. */
+#define _POSIX2_C_DEV 200112L
+
+/* If defined, the implementation supports the
+ Software Development Utilities Option. */
+#define _POSIX2_SW_DEV 200112L
+
+/* If defined, the implementation supports the
+ creation of locales with the localedef utility. */
+#define _POSIX2_LOCALEDEF 200112L
+
+/* X/Open version number to which the library conforms. It is selectable. */
+#ifdef __USE_UNIX98
+# define _XOPEN_VERSION 500
+#else
+# define _XOPEN_VERSION 4
+#endif
+
+/* Commands and utilities from XPG4 are available. */
+#define _XOPEN_XCU_VERSION 4
+
+/* We are compatible with the old published standards as well. */
+#define _XOPEN_XPG2 1
+#define _XOPEN_XPG3 1
+#define _XOPEN_XPG4 1
+
+/* The X/Open Unix extensions are available. */
+#define _XOPEN_UNIX 1
+
+/* Encryption is present. */
+#define _XOPEN_CRYPT 1
+
+/* The enhanced internationalization capabilities according to XPG4.2
+ are present. */
+#define _XOPEN_ENH_I18N 1
+
+/* The legacy interfaces are also available. */
+#define _XOPEN_LEGACY 1
+
+
+/* Get values of POSIX options:
+
+ If these symbols are defined, the corresponding features are
+ always available. If not, they may be available sometimes.
+ The current values can be obtained with `sysconf'.
+
+ _POSIX_JOB_CONTROL Job control is supported.
+ _POSIX_SAVED_IDS Processes have a saved set-user-ID
+ and a saved set-group-ID.
+ _POSIX_REALTIME_SIGNALS Real-time, queued signals are supported.
+ _POSIX_PRIORITY_SCHEDULING Priority scheduling is supported.
+ _POSIX_TIMERS POSIX.4 clocks and timers are supported.
+ _POSIX_ASYNCHRONOUS_IO Asynchronous I/O is supported.
+ _POSIX_PRIORITIZED_IO Prioritized asynchronous I/O is supported.
+ _POSIX_SYNCHRONIZED_IO Synchronizing file data is supported.
+ _POSIX_FSYNC The fsync function is present.
+ _POSIX_MAPPED_FILES Mapping of files to memory is supported.
+ _POSIX_MEMLOCK Locking of all memory is supported.
+ _POSIX_MEMLOCK_RANGE Locking of ranges of memory is supported.
+ _POSIX_MEMORY_PROTECTION Setting of memory protections is supported.
+ _POSIX_MESSAGE_PASSING POSIX.4 message queues are supported.
+ _POSIX_SEMAPHORES POSIX.4 counting semaphores are supported.
+ _POSIX_SHARED_MEMORY_OBJECTS POSIX.4 shared memory objects are supported.
+ _POSIX_THREADS POSIX.1c pthreads are supported.
+ _POSIX_THREAD_ATTR_STACKADDR Thread stack address attribute option supported.
+ _POSIX_THREAD_ATTR_STACKSIZE Thread stack size attribute option supported.
+ _POSIX_THREAD_SAFE_FUNCTIONS Thread-safe functions are supported.
+ _POSIX_THREAD_PRIORITY_SCHEDULING
+ POSIX.1c thread execution scheduling supported.
+ _POSIX_THREAD_PRIO_INHERIT Thread priority inheritance option supported.
+ _POSIX_THREAD_PRIO_PROTECT Thread priority protection option supported.
+ _POSIX_THREAD_PROCESS_SHARED Process-shared synchronization supported.
+ _POSIX_PII Protocol-independent interfaces are supported.
+ _POSIX_PII_XTI XTI protocol-indep. interfaces are supported.
+ _POSIX_PII_SOCKET Socket protocol-indep. interfaces are supported.
+ _POSIX_PII_INTERNET Internet family of protocols supported.
+ _POSIX_PII_INTERNET_STREAM Connection-mode Internet protocol supported.
+ _POSIX_PII_INTERNET_DGRAM Connectionless Internet protocol supported.
+ _POSIX_PII_OSI ISO/OSI family of protocols supported.
+ _POSIX_PII_OSI_COTS Connection-mode ISO/OSI service supported.
+ _POSIX_PII_OSI_CLTS Connectionless ISO/OSI service supported.
+ _POSIX_POLL Implementation supports `poll' function.
+ _POSIX_SELECT Implementation supports `select' and `pselect'.
+
+ _XOPEN_REALTIME X/Open realtime support is available.
+ _XOPEN_REALTIME_THREADS X/Open realtime thread support is available.
+ _XOPEN_SHM Shared memory interface according to XPG4.2.
+
+ _XBS5_ILP32_OFF32 Implementation provides environment with 32-bit
+ int, long, pointer, and off_t types.
+ _XBS5_ILP32_OFFBIG Implementation provides environment with 32-bit
+ int, long, and pointer and off_t with at least
+ 64 bits.
+ _XBS5_LP64_OFF64 Implementation provides environment with 32-bit
+ int, and 64-bit long, pointer, and off_t types.
+ _XBS5_LPBIG_OFFBIG Implementation provides environment with at
+ least 32 bits int and long, pointer, and off_t
+ with at least 64 bits.
+
+ If any of these symbols is defined as -1, the corresponding option is not
+ true for any file. If any is defined as other than -1, the corresponding
+ option is true for all files. If a symbol is not defined at all, the value
+ for a specific file can be obtained from `pathconf' and `fpathconf'.
+
+ _POSIX_CHOWN_RESTRICTED Only the super user can use `chown' to change
+ the owner of a file. `chown' can only be used
+ to change the group ID of a file to a group of
+ which the calling process is a member.
+ _POSIX_NO_TRUNC Pathname components longer than
+ NAME_MAX generate an error.
+ _POSIX_VDISABLE If defined, if the value of an element of the
+ `c_cc' member of `struct termios' is
+ _POSIX_VDISABLE, no character will have the
+ effect associated with that element.
+ _POSIX_SYNC_IO Synchronous I/O may be performed.
+ _POSIX_ASYNC_IO Asynchronous I/O may be performed.
+ _POSIX_PRIO_IO Prioritized Asynchronous I/O may be performed.
+
+ Support for the Large File Support interface is not generally available.
+ If it is available the following constants are defined to one.
+ _LFS64_LARGEFILE Low-level I/O supports large files.
+ _LFS64_STDIO Standard I/O supports large files.
+ */
+
+#include <bits/posix_opt.h>
+
+/* Get the environment definitions from Unix98. */
+#ifdef __USE_UNIX98
+# include <bits/environments.h>
+#endif
+
+/* Standard file descriptors. */
+#define STDIN_FILENO 0 /* Standard input. */
+#define STDOUT_FILENO 1 /* Standard output. */
+#define STDERR_FILENO 2 /* Standard error output. */
+
+
+/* All functions that are not declared anywhere else. */
+
+#include <bits/types.h>
+
+#ifndef __ssize_t_defined
+typedef __ssize_t ssize_t;
+# define __ssize_t_defined
+#endif
+
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+#if defined __USE_XOPEN || defined __USE_XOPEN2K
+/* The Single Unix specification says that some more types are
+ available here. */
+# ifndef __gid_t_defined
+typedef __gid_t gid_t;
+# define __gid_t_defined
+# endif
+
+# ifndef __uid_t_defined
+typedef __uid_t uid_t;
+# define __uid_t_defined
+# endif
+
+# ifndef __off_t_defined
+# ifndef __USE_FILE_OFFSET64
+typedef __off_t off_t;
+# else
+typedef __off64_t off_t;
+# endif
+# define __off_t_defined
+# endif
+# if defined __USE_LARGEFILE64 && !defined __off64_t_defined
+typedef __off64_t off64_t;
+# define __off64_t_defined
+# endif
+
+# ifndef __useconds_t_defined
+typedef __useconds_t useconds_t;
+# define __useconds_t_defined
+# endif
+
+# ifndef __pid_t_defined
+typedef __pid_t pid_t;
+# define __pid_t_defined
+# endif
+#endif /* X/Open */
+
+#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
+# ifndef __intptr_t_defined
+typedef __intptr_t intptr_t;
+# define __intptr_t_defined
+# endif
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN
+# ifndef __socklen_t_defined
+typedef __socklen_t socklen_t;
+# define __socklen_t_defined
+# endif
+#endif
+
+/* Values for the second argument to access.
+ These may be OR'd together. */
+#define R_OK 4 /* Test for read permission. */
+#define W_OK 2 /* Test for write permission. */
+#define X_OK 1 /* Test for execute permission. */
+#define F_OK 0 /* Test for existence. */
+
+/* Test for access to NAME using the real UID and real GID. */
+extern int access (__const char *__name, int __type) __THROW __nonnull ((1));
+
+#ifdef __USE_GNU
+/* Test for access to NAME using the effective UID and GID
+ (as normal file operations use). */
+extern int euidaccess (__const char *__name, int __type)
+ __THROW __nonnull ((1));
+
+/* An alias for `euidaccess', used by some other systems. */
+extern int eaccess (__const char *__name, int __type)
+ __THROW __nonnull ((1));
+#endif
+
+#ifdef __USE_ATFILE
+/* Test for access to FILE relative to the directory FD is open on.
+ If AT_EACCESS is set in FLAG, then use effective IDs like `eaccess',
+ otherwise use real IDs like `access'. */
+extern int faccessat (int __fd, __const char *__file, int __type, int __flag)
+ __THROW __nonnull ((2)) __wur;
+#endif /* Use GNU. */
+
+
+/* Values for the WHENCE argument to lseek. */
+#ifndef _STDIO_H /* <stdio.h> has the same definitions. */
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Seek from end of file. */
+#endif
+
+#if defined __USE_BSD && !defined L_SET
+/* Old BSD names for the same constants; just for compatibility. */
+# define L_SET SEEK_SET
+# define L_INCR SEEK_CUR
+# define L_XTND SEEK_END
+#endif
+
+
+/* Move FD's file position to OFFSET bytes from the
+ beginning of the file (if WHENCE is SEEK_SET),
+ the current position (if WHENCE is SEEK_CUR),
+ or the end of the file (if WHENCE is SEEK_END).
+ Return the new file position. */
+#ifndef __USE_FILE_OFFSET64
+extern __off_t lseek (int __fd, __off_t __offset, int __whence) __THROW;
+#else
+# ifdef __REDIRECT_NTH
+extern __off64_t __REDIRECT_NTH (lseek,
+ (int __fd, __off64_t __offset, int __whence),
+ lseek64);
+# else
+# define lseek lseek64
+# endif
+#endif
+#ifdef __USE_LARGEFILE64
+extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
+ __THROW;
+#endif
+
+/* Close the file descriptor FD.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int close (int __fd);
+
+/* Read NBYTES into BUF from FD. Return the
+ number read, -1 for errors or 0 for EOF.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur;
+
+/* Write N bytes of BUF to FD. Return the number written, or -1.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t write (int __fd, __const void *__buf, size_t __n) __wur;
+
+#ifdef __USE_UNIX98
+# ifndef __USE_FILE_OFFSET64
+/* Read NBYTES into BUF from FD at the given position OFFSET without
+ changing the file pointer. Return the number read, -1 for errors
+ or 0 for EOF.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t pread (int __fd, void *__buf, size_t __nbytes,
+ __off_t __offset) __wur;
+
+/* Write N bytes of BUF to FD at the given position OFFSET without
+ changing the file pointer. Return the number written, or -1.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t pwrite (int __fd, __const void *__buf, size_t __n,
+ __off_t __offset) __wur;
+# else
+# ifdef __REDIRECT
+extern ssize_t __REDIRECT (pread, (int __fd, void *__buf, size_t __nbytes,
+ __off64_t __offset),
+ pread64) __wur;
+extern ssize_t __REDIRECT (pwrite, (int __fd, __const void *__buf,
+ size_t __nbytes, __off64_t __offset),
+ pwrite64) __wur;
+# else
+# define pread pread64
+# define pwrite pwrite64
+# endif
+# endif
+
+# ifdef __USE_LARGEFILE64
+/* Read NBYTES into BUF from FD at the given position OFFSET without
+ changing the file pointer. Return the number read, -1 for errors
+ or 0 for EOF. */
+extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
+ __off64_t __offset) __wur;
+/* Write N bytes of BUF to FD at the given position OFFSET without
+ changing the file pointer. Return the number written, or -1. */
+extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n,
+ __off64_t __offset) __wur;
+# endif
+#endif
+
+/* Create a one-way communication channel (pipe).
+ If successful, two file descriptors are stored in PIPEDES;
+ bytes written on PIPEDES[1] can be read from PIPEDES[0].
+ Returns 0 if successful, -1 if not. */
+extern int pipe (int __pipedes[2]) __THROW __wur;
+
+/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM.
+ If SECONDS is zero, any currently scheduled alarm will be cancelled.
+ The function returns the number of seconds remaining until the last
+ alarm scheduled would have signaled, or zero if there wasn't one.
+ There is no return value to indicate an error, but you can set `errno'
+ to 0 and check its value after calling `alarm', and this might tell you.
+ The signal may come late due to processor scheduling. */
+extern unsigned int alarm (unsigned int __seconds) __THROW;
+
+/* Make the process sleep for SECONDS seconds, or until a signal arrives
+ and is not ignored. The function returns the number of seconds less
+ than SECONDS which it actually slept (thus zero if it slept the full time).
+ If a signal handler does a `longjmp' or modifies the handling of the
+ SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
+ signal afterwards is undefined. There is no return value to indicate
+ error, but if `sleep' returns SECONDS, it probably didn't work.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern unsigned int sleep (unsigned int __seconds);
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Set an alarm to go off (generating a SIGALRM signal) in VALUE
+ microseconds. If INTERVAL is nonzero, when the alarm goes off, the
+ timer is reset to go off every INTERVAL microseconds thereafter.
+ Returns the number of microseconds remaining before the alarm. */
+extern __useconds_t ualarm (__useconds_t __value, __useconds_t __interval)
+ __THROW;
+
+/* Sleep USECONDS microseconds, or until a signal arrives that is not blocked
+ or ignored.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int usleep (__useconds_t __useconds);
+#endif
+
+
+/* Suspend the process until a signal arrives.
+ This always returns -1 and sets `errno' to EINTR.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int pause (void);
+
+
+/* Change the owner and group of FILE. */
+extern int chown (__const char *__file, __uid_t __owner, __gid_t __group)
+ __THROW __nonnull ((1)) __wur;
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Change the owner and group of the file that FD is open on. */
+extern int fchown (int __fd, __uid_t __owner, __gid_t __group) __THROW __wur;
+
+
+/* Change owner and group of FILE, if it is a symbolic
+ link the ownership of the symbolic link is changed. */
+extern int lchown (__const char *__file, __uid_t __owner, __gid_t __group)
+ __THROW __nonnull ((1)) __wur;
+
+#endif /* Use BSD || X/Open Unix. */
+
+#ifdef __USE_ATFILE
+/* Change the owner and group of FILE relative to the directory FD is open
+ on. */
+extern int fchownat (int __fd, __const char *__file, __uid_t __owner,
+ __gid_t __group, int __flag)
+ __THROW __nonnull ((2)) __wur;
+#endif /* Use GNU. */
+
+/* Change the process's working directory to PATH. */
+extern int chdir (__const char *__path) __THROW __nonnull ((1)) __wur;
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Change the process's working directory to the one FD is open on. */
+extern int fchdir (int __fd) __THROW __wur;
+#endif
+
+/* Get the pathname of the current working directory,
+ and put it in SIZE bytes of BUF. Returns NULL if the
+ directory couldn't be determined or SIZE was too small.
+ If successful, returns BUF. In GNU, if BUF is NULL,
+ an array is allocated with `malloc'; the array is SIZE
+ bytes long, unless SIZE == 0, in which case it is as
+ big as necessary. */
+extern char *getcwd (char *__buf, size_t __size) __THROW __wur;
+
+#ifdef __USE_GNU
+/* Return a malloc'd string containing the current directory name.
+ If the environment variable `PWD' is set, and its value is correct,
+ that value is used. */
+extern char *get_current_dir_name (void) __THROW;
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Put the absolute pathname of the current working directory in BUF.
+ If successful, return BUF. If not, put an error message in
+ BUF and return NULL. BUF should be at least PATH_MAX bytes long. */
+extern char *getwd (char *__buf)
+ __THROW __nonnull ((1)) __attribute_deprecated__ __wur;
+#endif
+
+
+/* Duplicate FD, returning a new file descriptor on the same file. */
+extern int dup (int __fd) __THROW __wur;
+
+/* Duplicate FD to FD2, closing FD2 and making it open on the same file. */
+extern int dup2 (int __fd, int __fd2) __THROW;
+
+/* NULL-terminated array of "NAME=VALUE" environment variables. */
+extern char **__environ;
+#ifdef __USE_GNU
+extern char **environ;
+#endif
+
+
+/* Replace the current process, executing PATH with arguments ARGV and
+ environment ENVP. ARGV and ENVP are terminated by NULL pointers. */
+extern int execve (__const char *__path, char *__const __argv[],
+ char *__const __envp[]) __THROW __nonnull ((1));
+
+#ifdef __USE_GNU
+/* Execute the file FD refers to, overlaying the running program image.
+ ARGV and ENVP are passed to the new program, as for `execve'. */
+extern int fexecve (int __fd, char *__const __argv[], char *__const __envp[])
+ __THROW;
+#endif
+
+
+/* Execute PATH with arguments ARGV and environment from `environ'. */
+extern int execv (__const char *__path, char *__const __argv[])
+ __THROW __nonnull ((1));
+
+/* Execute PATH with all arguments after PATH until a NULL pointer,
+ and the argument after that for environment. */
+extern int execle (__const char *__path, __const char *__arg, ...)
+ __THROW __nonnull ((1));
+
+/* Execute PATH with all arguments after PATH until
+ a NULL pointer and environment from `environ'. */
+extern int execl (__const char *__path, __const char *__arg, ...)
+ __THROW __nonnull ((1));
+
+/* Execute FILE, searching in the `PATH' environment variable if it contains
+ no slashes, with arguments ARGV and environment from `environ'. */
+extern int execvp (__const char *__file, char *__const __argv[])
+ __THROW __nonnull ((1));
+
+/* Execute FILE, searching in the `PATH' environment variable if
+ it contains no slashes, with all arguments after FILE until a
+ NULL pointer and environment from `environ'. */
+extern int execlp (__const char *__file, __const char *__arg, ...)
+ __THROW __nonnull ((1));
+
+
+#if defined __USE_MISC || defined __USE_XOPEN
+/* Add INC to priority of the current process. */
+extern int nice (int __inc) __THROW __wur;
+#endif
+
+
+/* Terminate program execution with the low-order 8 bits of STATUS. */
+extern void _exit (int __status) __attribute__ ((__noreturn__));
+
+
+/* Get the `_PC_*' symbols for the NAME argument to `pathconf' and `fpathconf';
+ the `_SC_*' symbols for the NAME argument to `sysconf';
+ and the `_CS_*' symbols for the NAME argument to `confstr'. */
+#include <bits/confname.h>
+
+/* Get file-specific configuration information about PATH. */
+extern long int pathconf (__const char *__path, int __name)
+ __THROW __nonnull ((1));
+
+/* Get file-specific configuration about descriptor FD. */
+extern long int fpathconf (int __fd, int __name) __THROW;
+
+/* Get the value of the system variable NAME. */
+extern long int sysconf (int __name) __THROW __attribute__ ((__const__));
+
+#ifdef __USE_POSIX2
+/* Get the value of the string-valued system variable NAME. */
+extern size_t confstr (int __name, char *__buf, size_t __len) __THROW;
+#endif
+
+
+/* Get the process ID of the calling process. */
+extern __pid_t getpid (void) __THROW;
+
+/* Get the process ID of the calling process's parent. */
+extern __pid_t getppid (void) __THROW;
+
+/* Get the process group ID of the calling process.
+ This function is different on old BSD. */
+#ifndef __FAVOR_BSD
+extern __pid_t getpgrp (void) __THROW;
+#else
+# ifdef __REDIRECT_NTH
+extern __pid_t __REDIRECT_NTH (getpgrp, (__pid_t __pid), __getpgid);
+# else
+# define getpgrp __getpgid
+# endif
+#endif
+
+/* Get the process group ID of process PID. */
+extern __pid_t __getpgid (__pid_t __pid) __THROW;
+#ifdef __USE_XOPEN_EXTENDED
+extern __pid_t getpgid (__pid_t __pid) __THROW;
+#endif
+
+
+/* Set the process group ID of the process matching PID to PGID.
+ If PID is zero, the current process's process group ID is set.
+ If PGID is zero, the process ID of the process is used. */
+extern int setpgid (__pid_t __pid, __pid_t __pgid) __THROW;
+
+#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Both System V and BSD have `setpgrp' functions, but with different
+ calling conventions. The BSD function is the same as POSIX.1 `setpgid'
+ (above). The System V function takes no arguments and puts the calling
+ process in its on group like `setpgid (0, 0)'.
+
+ New programs should always use `setpgid' instead.
+
+ The default in GNU is to provide the System V function. The BSD
+ function is available under -D_BSD_SOURCE. */
+
+# ifndef __FAVOR_BSD
+
+/* Set the process group ID of the calling process to its own PID.
+ This is exactly the same as `setpgid (0, 0)'. */
+extern int setpgrp (void) __THROW;
+
+# else
+
+/* Another name for `setpgid' (above). */
+# ifdef __REDIRECT_NTH
+extern int __REDIRECT_NTH (setpgrp, (__pid_t __pid, __pid_t __pgrp), setpgid);
+# else
+# define setpgrp setpgid
+# endif
+
+# endif /* Favor BSD. */
+#endif /* Use SVID or BSD. */
+
+/* Create a new session with the calling process as its leader.
+ The process group IDs of the session and the calling process
+ are set to the process ID of the calling process, which is returned. */
+extern __pid_t setsid (void) __THROW;
+
+#ifdef __USE_XOPEN_EXTENDED
+/* Return the session ID of the given process. */
+extern __pid_t getsid (__pid_t __pid) __THROW;
+#endif
+
+/* Get the real user ID of the calling process. */
+extern __uid_t getuid (void) __THROW;
+
+/* Get the effective user ID of the calling process. */
+extern __uid_t geteuid (void) __THROW;
+
+/* Get the real group ID of the calling process. */
+extern __gid_t getgid (void) __THROW;
+
+/* Get the effective group ID of the calling process. */
+extern __gid_t getegid (void) __THROW;
+
+/* If SIZE is zero, return the number of supplementary groups
+ the calling process is in. Otherwise, fill in the group IDs
+ of its supplementary groups in LIST and return the number written. */
+extern int getgroups (int __size, __gid_t __list[]) __THROW __wur;
+
+#ifdef __USE_GNU
+/* Return nonzero iff the calling process is in group GID. */
+extern int group_member (__gid_t __gid) __THROW;
+#endif
+
+/* Set the user ID of the calling process to UID.
+ If the calling process is the super-user, set the real
+ and effective user IDs, and the saved set-user-ID to UID;
+ if not, the effective user ID is set to UID. */
+extern int setuid (__uid_t __uid) __THROW;
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Set the real user ID of the calling process to RUID,
+ and the effective user ID of the calling process to EUID. */
+extern int setreuid (__uid_t __ruid, __uid_t __euid) __THROW;
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN2K
+/* Set the effective user ID of the calling process to UID. */
+extern int seteuid (__uid_t __uid) __THROW;
+#endif /* Use BSD. */
+
+/* Set the group ID of the calling process to GID.
+ If the calling process is the super-user, set the real
+ and effective group IDs, and the saved set-group-ID to GID;
+ if not, the effective group ID is set to GID. */
+extern int setgid (__gid_t __gid) __THROW;
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Set the real group ID of the calling process to RGID,
+ and the effective group ID of the calling process to EGID. */
+extern int setregid (__gid_t __rgid, __gid_t __egid) __THROW;
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN2K
+/* Set the effective group ID of the calling process to GID. */
+extern int setegid (__gid_t __gid) __THROW;
+#endif /* Use BSD. */
+
+#ifdef __USE_GNU
+/* Fetch the real user ID, effective user ID, and saved-set user ID,
+ of the calling process. */
+extern int getresuid (__uid_t *__ruid, __uid_t *__euid, __uid_t *__suid)
+ __THROW;
+
+/* Fetch the real group ID, effective group ID, and saved-set group ID,
+ of the calling process. */
+extern int getresgid (__gid_t *__rgid, __gid_t *__egid, __gid_t *__sgid)
+ __THROW;
+
+/* Set the real user ID, effective user ID, and saved-set user ID,
+ of the calling process to RUID, EUID, and SUID, respectively. */
+extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid)
+ __THROW;
+
+/* Set the real group ID, effective group ID, and saved-set group ID,
+ of the calling process to RGID, EGID, and SGID, respectively. */
+extern int setresgid (__gid_t __rgid, __gid_t __egid, __gid_t __sgid)
+ __THROW;
+#endif
+
+
+/* Clone the calling process, creating an exact copy.
+ Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+extern __pid_t fork (void) __THROW;
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+/* Clone the calling process, but without copying the whole address space.
+ The calling process is suspended until the new process exits or is
+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+extern __pid_t vfork (void) __THROW;
+#endif /* Use BSD. */
+
+
+/* Return the pathname of the terminal FD is open on, or NULL on errors.
+ The returned storage is good only until the next call to this function. */
+extern char *ttyname (int __fd) __THROW;
+
+/* Store at most BUFLEN characters of the pathname of the terminal FD is
+ open on in BUF. Return 0 on success, otherwise an error number. */
+extern int ttyname_r (int __fd, char *__buf, size_t __buflen)
+ __THROW __nonnull ((2)) __wur;
+
+/* Return 1 if FD is a valid descriptor associated
+ with a terminal, zero if not. */
+extern int isatty (int __fd) __THROW;
+
+#if defined __USE_BSD \
+ || (defined __USE_XOPEN_EXTENDED && !defined __USE_UNIX98)
+/* Return the index into the active-logins file (utmp) for
+ the controlling terminal. */
+extern int ttyslot (void) __THROW;
+#endif
+
+
+/* Make a link to FROM named TO. */
+extern int link (__const char *__from, __const char *__to)
+ __THROW __nonnull ((1, 2)) __wur;
+
+#ifdef __USE_ATFILE
+/* Like link but relative paths in TO and FROM are interpreted relative
+ to FROMFD and TOFD respectively. */
+extern int linkat (int __fromfd, __const char *__from, int __tofd,
+ __const char *__to, int __flags)
+ __THROW __nonnull ((2, 4)) __wur;
+#endif
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
+/* Make a symbolic link to FROM named TO. */
+extern int symlink (__const char *__from, __const char *__to)
+ __THROW __nonnull ((1, 2)) __wur;
+
+/* Read the contents of the symbolic link PATH into no more than
+ LEN bytes of BUF. The contents are not null-terminated.
+ Returns the number of characters read, or -1 for errors. */
+extern ssize_t readlink (__const char *__restrict __path,
+ char *__restrict __buf, size_t __len)
+ __THROW __nonnull ((1, 2)) __wur;
+#endif /* Use BSD. */
+
+#ifdef __USE_ATFILE
+/* Like symlink but a relative path in TO is interpreted relative to TOFD. */
+extern int symlinkat (__const char *__from, int __tofd,
+ __const char *__to) __THROW __nonnull ((1, 3)) __wur;
+
+/* Like readlink but a relative PATH is interpreted relative to FD. */
+extern ssize_t readlinkat (int __fd, __const char *__restrict __path,
+ char *__restrict __buf, size_t __len)
+ __THROW __nonnull ((2, 3)) __wur;
+#endif
+
+/* Remove the link NAME. */
+extern int unlink (__const char *__name) __THROW __nonnull ((1));
+
+#ifdef __USE_ATFILE
+/* Remove the link NAME relative to FD. */
+extern int unlinkat (int __fd, __const char *__name, int __flag)
+ __THROW __nonnull ((2));
+#endif
+
+/* Remove the directory PATH. */
+extern int rmdir (__const char *__path) __THROW __nonnull ((1));
+
+
+/* Return the foreground process group ID of FD. */
+extern __pid_t tcgetpgrp (int __fd) __THROW;
+
+/* Set the foreground process group ID of FD set PGRP_ID. */
+extern int tcsetpgrp (int __fd, __pid_t __pgrp_id) __THROW;
+
+
+/* Return the login name of the user.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern char *getlogin (void);
+#if defined __USE_REENTRANT || defined __USE_UNIX98
+/* Return at most NAME_LEN characters of the login name of the user in NAME.
+ If it cannot be determined or some other error occurred, return the error
+ code. Otherwise return 0.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern int getlogin_r (char *__name, size_t __name_len) __nonnull ((1));
+#endif
+
+#ifdef __USE_BSD
+/* Set the login name returned by `getlogin'. */
+extern int setlogin (__const char *__name) __THROW __nonnull ((1));
+#endif
+
+
+#ifdef __USE_POSIX2
+/* Get definitions and prototypes for functions to process the
+ arguments in ARGV (ARGC of them, minus the program name) for
+ options given in OPTS. */
+# define __need_getopt
+# include <getopt.h>
+#endif
+
+
+#if defined __USE_BSD || defined __USE_UNIX98
+/* Put the name of the current host in no more than LEN bytes of NAME.
+ The result is null-terminated if LEN is large enough for the full
+ name and the terminator. */
+extern int gethostname (char *__name, size_t __len) __THROW __nonnull ((1));
+#endif
+
+
+#if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98)
+/* Set the name of the current host to NAME, which is LEN bytes long.
+ This call is restricted to the super-user. */
+extern int sethostname (__const char *__name, size_t __len)
+ __THROW __nonnull ((1)) __wur;
+
+/* Set the current machine's Internet number to ID.
+ This call is restricted to the super-user. */
+extern int sethostid (long int __id) __THROW __wur;
+
+
+/* Get and set the NIS (aka YP) domain name, if any.
+ Called just like `gethostname' and `sethostname'.
+ The NIS domain name is usually the empty string when not using NIS. */
+extern int getdomainname (char *__name, size_t __len)
+ __THROW __nonnull ((1)) __wur;
+extern int setdomainname (__const char *__name, size_t __len)
+ __THROW __nonnull ((1)) __wur;
+
+
+/* Revoke access permissions to all processes currently communicating
+ with the control terminal, and then send a SIGHUP signal to the process
+ group of the control terminal. */
+extern int vhangup (void) __THROW;
+
+/* Revoke the access of all descriptors currently open on FILE. */
+extern int revoke (__const char *__file) __THROW __nonnull ((1)) __wur;
+
+
+/* Enable statistical profiling, writing samples of the PC into at most
+ SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling
+ is enabled, the system examines the user PC and increments
+ SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536]. If SCALE is zero,
+ disable profiling. Returns zero on success, -1 on error. */
+extern int profil (unsigned short int *__sample_buffer, size_t __size,
+ size_t __offset, unsigned int __scale)
+ __THROW __nonnull ((1));
+
+
+/* Turn accounting on if NAME is an existing file. The system will then write
+ a record for each process as it terminates, to this file. If NAME is NULL,
+ turn accounting off. This call is restricted to the super-user. */
+extern int acct (__const char *__name) __THROW;
+
+
+/* Successive calls return the shells listed in `/etc/shells'. */
+extern char *getusershell (void) __THROW;
+extern void endusershell (void) __THROW; /* Discard cached info. */
+extern void setusershell (void) __THROW; /* Rewind and re-read the file. */
+
+
+/* Put the program in the background, and dissociate from the controlling
+ terminal. If NOCHDIR is zero, do `chdir ("/")'. If NOCLOSE is zero,
+ redirects stdin, stdout, and stderr to /dev/null. */
+extern int daemon (int __nochdir, int __noclose) __THROW __wur;
+#endif /* Use BSD || X/Open. */
+
+
+#if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
+/* Make PATH be the root directory (the starting point for absolute paths).
+ This call is restricted to the super-user. */
+extern int chroot (__const char *__path) __THROW __nonnull ((1)) __wur;
+
+/* Prompt with PROMPT and read a string from the terminal without echoing.
+ Uses /dev/tty if possible; otherwise stderr and stdin. */
+extern char *getpass (__const char *__prompt) __nonnull ((1));
+#endif /* Use BSD || X/Open. */
+
+
+#if defined __USE_BSD || defined __USE_XOPEN
+/* Make all changes done to FD actually appear on disk.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int fsync (int __fd);
+#endif /* Use BSD || X/Open. */
+
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
+
+/* Return identifier for the current host. */
+extern long int gethostid (void);
+
+/* Make all changes done to all files actually appear on disk. */
+extern void sync (void) __THROW;
+
+
+/* Return the number of bytes in a page. This is the system's page size,
+ which is not necessarily the same as the hardware page size. */
+extern int getpagesize (void) __THROW __attribute__ ((__const__));
+
+
+/* Return the maximum number of file descriptors
+ the current process could possibly have. */
+extern int getdtablesize (void) __THROW;
+
+
+/* Truncate FILE to LENGTH bytes. */
+# ifndef __USE_FILE_OFFSET64
+extern int truncate (__const char *__file, __off_t __length)
+ __THROW __nonnull ((1)) __wur;
+# else
+# ifdef __REDIRECT_NTH
+extern int __REDIRECT_NTH (truncate,
+ (__const char *__file, __off64_t __length),
+ truncate64) __nonnull ((1)) __wur;
+# else
+# define truncate truncate64
+# endif
+# endif
+# ifdef __USE_LARGEFILE64
+extern int truncate64 (__const char *__file, __off64_t __length)
+ __THROW __nonnull ((1)) __wur;
+# endif
+
+#endif /* Use BSD || X/Open Unix. */
+
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
+
+/* Truncate the file FD is open on to LENGTH bytes. */
+# ifndef __USE_FILE_OFFSET64
+extern int ftruncate (int __fd, __off_t __length) __THROW __wur;
+# else
+# ifdef __REDIRECT_NTH
+extern int __REDIRECT_NTH (ftruncate, (int __fd, __off64_t __length),
+ ftruncate64) __wur;
+# else
+# define ftruncate ftruncate64
+# endif
+# endif
+# ifdef __USE_LARGEFILE64
+extern int ftruncate64 (int __fd, __off64_t __length) __THROW __wur;
+# endif
+
+#endif /* Use BSD || X/Open Unix || POSIX 2003. */
+
+
+#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
+
+/* Set the end of accessible data space (aka "the break") to ADDR.
+ Returns zero on success and -1 for errors (with errno set). */
+extern int brk (void *__addr) __THROW __wur;
+
+/* Increase or decrease the end of accessible data space by DELTA bytes.
+ If successful, returns the address the previous end of data space
+ (i.e. the beginning of the new space, if DELTA > 0);
+ returns (void *) -1 for errors (with errno set). */
+extern void *sbrk (intptr_t __delta) __THROW;
+#endif
+
+
+#ifdef __USE_MISC
+/* Invoke `system call' number SYSNO, passing it the remaining arguments.
+ This is completely system-dependent, and not often useful.
+
+ In Unix, `syscall' sets `errno' for all errors and most calls return -1
+ for errors; in many systems you cannot pass arguments or get return
+ values for all system calls (`pipe', `fork', and `getppid' typically
+ among them).
+
+ In Mach, all system calls take normal arguments and always return an
+ error code (zero for success). */
+extern long int syscall (long int __sysno, ...) __THROW;
+
+#endif /* Use misc. */
+
+
+#if (defined __USE_MISC || defined __USE_XOPEN_EXTENDED) && !defined F_LOCK
+/* NOTE: These declarations also appear in <fcntl.h>; be sure to keep both
+ files consistent. Some systems have them there and some here, and some
+ software depends on the macros being defined without including both. */
+
+/* `lockf' is a simpler interface to the locking facilities of `fcntl'.
+ LEN is always relative to the current file position.
+ The CMD argument is one of the following.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+
+# define F_ULOCK 0 /* Unlock a previously locked region. */
+# define F_LOCK 1 /* Lock a region for exclusive use. */
+# define F_TLOCK 2 /* Test and lock a region for exclusive use. */
+# define F_TEST 3 /* Test a region for other processes locks. */
+
+# ifndef __USE_FILE_OFFSET64
+extern int lockf (int __fd, int __cmd, __off_t __len) __wur;
+# else
+# ifdef __REDIRECT
+extern int __REDIRECT (lockf, (int __fd, int __cmd, __off64_t __len),
+ lockf64) __wur;
+# else
+# define lockf lockf64
+# endif
+# endif
+# ifdef __USE_LARGEFILE64
+extern int lockf64 (int __fd, int __cmd, __off64_t __len) __wur;
+# endif
+#endif /* Use misc and F_LOCK not already defined. */
+
+
+#ifdef __USE_GNU
+
+/* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
+ set to EINTR. */
+
+# define TEMP_FAILURE_RETRY(expression) \
+ (__extension__ \
+ ({ long int __result; \
+ do __result = (long int) (expression); \
+ while (__result == -1L && errno == EINTR); \
+ __result; }))
+#endif
+
+#if defined __USE_POSIX199309 || defined __USE_UNIX98
+/* Synchronize at least the data part of a file with the underlying
+ media. */
+extern int fdatasync (int __fildes) __THROW;
+#endif /* Use POSIX199309 */
+
+
+/* XPG4.2 specifies that prototypes for the encryption functions must
+ be defined here. */
+#ifdef __USE_XOPEN
+/* Encrypt at most 8 characters from KEY using salt to perturb DES. */
+extern char *crypt (__const char *__key, __const char *__salt)
+ __THROW __nonnull ((1, 2));
+
+/* Encrypt data in BLOCK in place if EDFLAG is zero; otherwise decrypt
+ block in place. */
+extern void encrypt (char *__block, int __edflag) __THROW __nonnull ((1));
+
+
+/* Swab pairs bytes in the first N bytes of the area pointed to by
+ FROM and copy the result to TO. The value of TO must not be in the
+ range [FROM - N + 1, FROM - 1]. If N is odd the first byte in FROM
+ is without partner. */
+extern void swab (__const void *__restrict __from, void *__restrict __to,
+ ssize_t __n) __THROW __nonnull ((1, 2));
+#endif
+
+
+/* The Single Unix specification demands this prototype to be here.
+ It is also found in <stdio.h>. */
+#ifdef __USE_XOPEN
+/* Return the name of the controlling terminal. */
+extern char *ctermid (char *__s) __THROW;
+#endif
+
+
+/* Define some macros helping to catch buffer overflows. */
+#if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus
+# include <bits/unistd.h>
+#endif
+
+__END_DECLS
+
+#endif /* unistd.h */
diff --git a/libc/posix/vfork.c b/libc/posix/vfork.c
new file mode 100644
index 000000000..d15841d71
--- /dev/null
+++ b/libc/posix/vfork.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 1992, 1995, 1997, 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* If we don't have vfork, fork is close enough. */
+
+__pid_t
+__vfork (void)
+{
+ return __fork ();
+}
+libc_hidden_def (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libc/posix/wait.c b/libc/posix/wait.c
new file mode 100644
index 000000000..b1c512ed3
--- /dev/null
+++ b/libc/posix/wait.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/wait.h>
+#include <errno.h>
+
+/* Wait for a child to die. When one does, put its status in *STAT_LOC
+ and return its process ID. For errors, return (pid_t) -1. */
+__pid_t
+__wait (__WAIT_STATUS_DEFN stat_loc)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (wait)
+
+weak_alias (__wait, wait)
+#include <stub-tag.h>
diff --git a/libc/posix/wait.h b/libc/posix/wait.h
new file mode 100644
index 000000000..d01b81125
--- /dev/null
+++ b/libc/posix/wait.h
@@ -0,0 +1 @@
+#include <sys/wait.h>
diff --git a/libc/posix/wait3.c b/libc/posix/wait3.c
new file mode 100644
index 000000000..479d99e3d
--- /dev/null
+++ b/libc/posix/wait3.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+/* Wait for a child to exit. When one does, put its status in *STAT_LOC and
+ return its process ID. For errors return (pid_t) -1. If USAGE is not nil,
+ store information about the child's resource usage (as a `struct rusage')
+ there. If the WUNTRACED bit is set in OPTIONS, return status for stopped
+ children; otherwise don't. */
+pid_t
+__wait3 (__WAIT_STATUS_DEFN stat_loc, int options, struct rusage *usage)
+{
+ if ((options & ~(WNOHANG|WUNTRACED)) != 0)
+ {
+ __set_errno (EINVAL);
+ return (pid_t) -1;
+ }
+
+ __set_errno (ENOSYS);
+ return (pid_t) -1;
+}
+stub_warning (wait3)
+
+weak_alias (__wait3, wait3)
+#include <stub-tag.h>
diff --git a/libc/posix/wait4.c b/libc/posix/wait4.c
new file mode 100644
index 000000000..b59bf87ff
--- /dev/null
+++ b/libc/posix/wait4.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+pid_t
+__wait4 (__pid_t pid, __WAIT_STATUS stat_loc, int options,
+ struct rusage *usage)
+{
+ __set_errno (ENOSYS);
+ return (pid_t) -1;
+}
+stub_warning (wait4)
+
+weak_alias (__wait4, wait4)
+#include <stub-tag.h>
diff --git a/libc/posix/waitid.c b/libc/posix/waitid.c
new file mode 100644
index 000000000..a9de1a19a
--- /dev/null
+++ b/libc/posix/waitid.c
@@ -0,0 +1,35 @@
+/* Stub version of waitid.
+ Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int
+__waitid (idtype, id, infop, options)
+ idtype_t idtype;
+ id_t id;
+ siginfo_t *infop;
+ int options;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+weak_alias (__waitid, waitid)
diff --git a/libc/posix/waitpid.c b/libc/posix/waitpid.c
new file mode 100644
index 000000000..9c7736e66
--- /dev/null
+++ b/libc/posix/waitpid.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1991,95,96,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+
+/* Wait for a child matching PID to die.
+ If PID is greater than 0, match any process whose process ID is PID.
+ If PID is (pid_t) -1, match any process.
+ If PID is (pid_t) 0, match any process with the
+ same process group as the current process.
+ If PID is less than -1, match any process whose
+ process group is the absolute value of PID.
+ If the WNOHANG bit is set in OPTIONS, and that child
+ is not already dead, return (pid_t) 0. If successful,
+ return PID and store the dead child's status in STAT_LOC.
+ Return (pid_t) -1 for errors. If the WUNTRACED bit is set in OPTIONS,
+ return status for stopped children; otherwise don't. */
+pid_t
+__libc_waitpid (pid_t pid, int *stat_loc, int options)
+{
+ if ((options & ~(WNOHANG|WUNTRACED)) != 0)
+ {
+ __set_errno (EINVAL);
+ return (pid_t) -1;
+ }
+
+ __set_errno (ENOSYS);
+ return (pid_t) -1;
+}
+weak_alias (__libc_waitpid, __waitpid)
+libc_hidden_weak (__waitpid)
+weak_alias (__libc_waitpid, waitpid)
+
+stub_warning (waitpid)
+#include <stub-tag.h>
diff --git a/libc/posix/wordexp-test.c b/libc/posix/wordexp-test.c
new file mode 100644
index 000000000..db418cede
--- /dev/null
+++ b/libc/posix/wordexp-test.c
@@ -0,0 +1,438 @@
+/* Copyright (C) 1997, 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wordexp.h>
+
+#define IFS " \n\t"
+
+struct test_case_struct
+{
+ int retval;
+ const char *env;
+ const char *words;
+ int flags;
+ size_t wordc;
+ const char *wordv[10];
+ const char *ifs;
+} test_case[] =
+ {
+ /* Simple word- and field-splitting */
+ { 0, NULL, "one", 0, 1, { "one", }, IFS },
+ { 0, NULL, "one two", 0, 2, { "one", "two", }, IFS },
+ { 0, NULL, "one two three", 0, 3, { "one", "two", "three", }, IFS },
+ { 0, NULL, " \tfoo\t\tbar ", 0, 2, { "foo", "bar", }, IFS },
+ { 0, NULL, "red , white blue", 0, 4, { "red", ",", "white", "blue", }, " ," },
+ { 0, NULL, "one two three", 0, 3, { "one", "two", "three", }, "" },
+ { 0, NULL, "one \"two three\"", 0, 2, { "one", "two three", }, IFS },
+ { 0, NULL, "one \"two three\"", 0, 2, { "one", "two three", }, "" },
+ { 0, "two three", "one \"$var\"", 0, 2, { "one", "two three", }, IFS },
+ { 0, "two three", "one $var", 0, 3, { "one", "two", "three", }, IFS },
+ { 0, "two three", "one \"$var\"", 0, 2, { "one", "two three", }, "" },
+ { 0, "two three", "one $var", 0, 2, { "one", "two three", }, "" },
+
+ /* The non-whitespace IFS char at the end delimits the second field
+ * but does NOT start a new field. */
+ { 0, ":abc:", "$var", 0, 2, { "", "abc", }, ":" },
+
+ { 0, NULL, "$(echo :abc:)", 0, 2, { "", "abc", }, ":" },
+ { 0, NULL, "$(echo :abc:\\ )", 0, 2, { "", "abc", }, ": " },
+ { 0, NULL, "$(echo :abc\\ )", 0, 2, { "", "abc", }, ": " },
+ { 0, ":abc:", "$(echo $var)", 0, 2, { "", "abc", }, ":" },
+ { 0, NULL, ":abc:", 0, 1, { ":abc:", }, ":" },
+ { 0, NULL, "$(echo :abc:)def", 0, 3, { "", "abc", "def", },
+ ":" },
+ { 0, NULL, "$(echo abc:de)f", 0, 2, { "abc", "def", }, ":" },
+ { 0, NULL, "$(echo abc:de)f:ghi", 0, 2, { "abc", "def:ghi", },
+ ":" },
+ { 0, NULL, "abc:d$(echo ef:ghi)", 0, 2, { "abc:def", "ghi", },
+ ":" },
+ { 0, "abc:", "$var$(echo def:ghi)", 0, 3, { "abc", "def",
+ "ghi", }, ":" },
+ { 0, "abc:d", "$var$(echo ef:ghi)", 0, 3, { "abc", "def",
+ "ghi", }, ":" },
+ { 0, "def:ghi", "$(echo abc:)$var", 0, 3, { "abc", "def",
+ "ghi", }, ":" },
+ { 0, "ef:ghi", "$(echo abc:d)$var", 0, 3, { "abc", "def",
+ "ghi", }, ":" },
+
+ /* Simple parameter expansion */
+ { 0, "foo", "${var}", 0, 1, { "foo", }, IFS },
+ { 0, "foo", "$var", 0, 1, { "foo", }, IFS },
+ { 0, "foo", "\\\"$var\\\"", 0, 1, { "\"foo\"", }, IFS },
+ { 0, "foo", "%$var%", 0, 1, { "%foo%", }, IFS },
+ { 0, "foo", "-$var-", 0, 1, { "-foo-", }, IFS },
+
+ /* Simple quote removal */
+ { 0, NULL, "\"quoted\"", 0, 1, { "quoted", }, IFS },
+ { 0, "foo", "\"$var\"\"$var\"", 0, 1, { "foofoo", }, IFS },
+ { 0, NULL, "'singly-quoted'", 0, 1, { "singly-quoted", }, IFS },
+ { 0, NULL, "contin\\\nuation", 0, 1, { "continuation", }, IFS },
+ { 0, NULL, "explicit ''", 0, 2, { "explicit", "", }, IFS },
+ { 0, NULL, "explicit \"\"", 0, 2, { "explicit", "", }, IFS },
+ { 0, NULL, "explicit ``", 0, 1, { "explicit", }, IFS },
+
+ /* Simple command substitution */
+ { 0, NULL, "$(echo hello)", 0, 1, { "hello", }, IFS },
+ { 0, NULL, "$( (echo hello) )", 0, 1, { "hello", }, IFS },
+ { 0, NULL, "$((echo hello);(echo there))", 0, 2, { "hello", "there", }, IFS },
+ { 0, NULL, "`echo one two`", 0, 2, { "one", "two", }, IFS },
+ { 0, NULL, "$(echo ')')", 0, 1, { ")" }, IFS },
+ { 0, NULL, "$(echo hello; echo)", 0, 1, { "hello", }, IFS },
+ { 0, NULL, "a$(echo b)c", 0, 1, { "abc", }, IFS },
+
+ /* Simple arithmetic expansion */
+ { 0, NULL, "$((1 + 1))", 0, 1, { "2", }, IFS },
+ { 0, NULL, "$((2-3))", 0, 1, { "-1", }, IFS },
+ { 0, NULL, "$((-1))", 0, 1, { "-1", }, IFS },
+ { 0, NULL, "$[50+20]", 0, 1, { "70", }, IFS },
+ { 0, NULL, "$(((2+3)*(4+5)))", 0, 1, { "45", }, IFS },
+ { 0, NULL, "$((010))", 0, 1, { "8" }, IFS },
+ { 0, NULL, "$((0x10))", 0, 1, { "16" }, IFS },
+ { 0, NULL, "$((010+0x10))", 0, 1, { "24" }, IFS },
+ { 0, NULL, "$((-010+0x10))", 0, 1, { "8" }, IFS },
+ { 0, NULL, "$((-0x10+010))", 0, 1, { "-8" }, IFS },
+
+ /* Advanced parameter expansion */
+ { 0, NULL, "${var:-bar}", 0, 1, { "bar", }, IFS },
+ { 0, NULL, "${var-bar}", 0, 1, { "bar", }, IFS },
+ { 0, "", "${var:-bar}", 0, 1, { "bar", }, IFS },
+ { 0, "foo", "${var:-bar}", 0, 1, { "foo", }, IFS },
+ { 0, "", "${var-bar}", 0, 0, { NULL, }, IFS },
+ { 0, NULL, "${var:=bar}", 0, 1, { "bar", }, IFS },
+ { 0, NULL, "${var=bar}", 0, 1, { "bar", }, IFS },
+ { 0, "", "${var:=bar}", 0, 1, { "bar", }, IFS },
+ { 0, "foo", "${var:=bar}", 0, 1, { "foo", }, IFS },
+ { 0, "", "${var=bar}", 0, 0, { NULL, }, IFS },
+ { 0, "foo", "${var:?bar}", 0, 1, { "foo", }, IFS },
+ { 0, NULL, "${var:+bar}", 0, 0, { NULL, }, IFS },
+ { 0, NULL, "${var+bar}", 0, 0, { NULL, }, IFS },
+ { 0, "", "${var:+bar}", 0, 0, { NULL, }, IFS },
+ { 0, "foo", "${var:+bar}", 0, 1, { "bar", }, IFS },
+ { 0, "", "${var+bar}", 0, 1, { "bar", }, IFS },
+ { 0, "12345", "${#var}", 0, 1, { "5", }, IFS },
+ { 0, NULL, "${var:-'}'}", 0, 1, { "}", }, IFS },
+ { 0, NULL, "${var-}", 0, 0, { NULL }, IFS },
+
+ { 0, "pizza", "${var#${var}}", 0, 0, { NULL }, IFS },
+ { 0, "pepperoni", "${var%$(echo oni)}", 0, 1, { "pepper" }, IFS },
+ { 0, "6pack", "${var#$((6))}", 0, 1, { "pack" }, IFS },
+ { 0, "b*witched", "${var##b*}", 0, 0, { NULL }, IFS },
+ { 0, "b*witched", "${var##\"b*\"}", 0, 1, { "witched" }, IFS },
+ { 0, "banana", "${var%na*}", 0, 1, { "bana", }, IFS },
+ { 0, "banana", "${var%%na*}", 0, 1, { "ba", }, IFS },
+ { 0, "borabora-island", "${var#*bora}", 0, 1, { "bora-island", }, IFS },
+ { 0, "borabora-island", "${var##*bora}", 0, 1, { "-island", }, IFS },
+ { 0, "coconut", "${var##\\*co}", 0, 1, { "coconut", }, IFS },
+ { 0, "100%", "${var%0%}", 0, 1, { "10" }, IFS },
+
+ /* Pathname expansion */
+ { 0, NULL, "???", 0, 2, { "one", "two", }, IFS },
+ { 0, NULL, "[ot]??", 0, 2, { "one", "two", }, IFS },
+ { 0, NULL, "t*", 0, 2, { "three", "two", }, IFS },
+ { 0, NULL, "\"t\"*", 0, 2, { "three", "two", }, IFS },
+
+ /* Nested constructs */
+ { 0, "one two", "$var", 0, 2, { "one", "two", }, IFS },
+ { 0, "one two three", "$var", 0, 3, { "one", "two", "three", }, IFS },
+ { 0, " \tfoo\t\tbar ", "$var", 0, 2, { "foo", "bar", }, IFS },
+ { 0, " red , white blue", "$var", 0, 3, { "red", "white", "blue", }, ", \n\t" },
+ { 0, " red , white blue", "\"$var\"", 0, 1, { " red , white blue", }, ", \n\t" },
+ { 0, NULL, "\"$(echo hello there)\"", 0, 1, { "hello there", }, IFS },
+ { 0, NULL, "\"$(echo \"hello there\")\"", 0, 1, { "hello there", }, IFS },
+ { 0, NULL, "${var=one two} \"$var\"", 0, 3, { "one", "two", "one two", }, IFS },
+ { 0, "1", "$(( $(echo 3)+$var ))", 0, 1, { "4", }, IFS },
+ { 0, NULL, "\"$(echo \"*\")\"", 0, 1, { "*", }, IFS },
+ { 0, NULL, "\"a\n\n$(echo)b\"", 0, 1, { "a\n\nb", }, IFS },
+ { 0, "foo", "*$var*", 0, 1, { "*foo*", }, IFS },
+ { 0, "o thr", "*$var*", 0, 2, { "two", "three" }, IFS },
+
+ /* Different IFS values */
+ { 0, "a b\tc\nd ", "$var", 0, 4, { "a", "b", "c", "d" }, NULL /* unset */ },
+ { 0, "a b\tc d ", "$var", 0, 1, { "a b\tc d " }, "" /* `null' */ },
+ { 0, "a,b c\n, d", "$var", 0, 3, { "a", "b c", " d" }, "\t\n," },
+
+ /* Other things that should succeed */
+ { 0, NULL, "\\*\"|&;<>\"\\(\\)\\{\\}", 0, 1, { "*|&;<>(){}", }, IFS },
+ { 0, "???", "$var", 0, 1, { "???", }, IFS },
+ { 0, NULL, "$var", 0, 0, { NULL, }, IFS },
+ { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS },
+ { 0, NULL, "", 0, 0, { NULL, }, IFS },
+
+ /* Flags not already covered (testit() has special handling for these) */
+ { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS },
+ { 0, NULL, "appended", WRDE_APPEND, 3, { "pre1", "pre2", "appended", }, IFS },
+ { 0, NULL, "appended", WRDE_DOOFFS|WRDE_APPEND, 3, { "pre1", "pre2", "appended", }, IFS },
+
+ /* Things that should fail */
+ { WRDE_BADCHAR, NULL, "new\nline", 0, 0, { NULL, }, "" /* \n not IFS */ },
+ { WRDE_BADCHAR, NULL, "pipe|symbol", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "&ampersand", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "semi;colon", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "<greater", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "less>", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "(open-paren", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "close-paren)", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "{open-brace", 0, 0, { NULL, }, IFS },
+ { WRDE_BADCHAR, NULL, "close-brace}", 0, 0, { NULL, }, IFS },
+ { WRDE_CMDSUB, NULL, "$(ls)", WRDE_NOCMD, 0, { NULL, }, IFS },
+ { WRDE_BADVAL, NULL, "$var", WRDE_UNDEF, 0, { NULL, }, IFS },
+ { WRDE_BADVAL, NULL, "$9", WRDE_UNDEF, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "$[50+20))", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "${%%noparam}", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "${missing-brace", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "$(for i in)", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
+
+ { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
+ };
+
+static int testit (struct test_case_struct *tc);
+static int tests;
+
+static void
+command_line_test (const char *words)
+{
+ wordexp_t we;
+ int i;
+ int retval = wordexp (words, &we, 0);
+ printf ("wordexp returned %d\n", retval);
+ for (i = 0; i < we.we_wordc; i++)
+ printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
+}
+
+int
+main (int argc, char *argv[])
+{
+ const char *globfile[] = { "one", "two", "three", NULL };
+ char tmpdir[32];
+ struct passwd *pw;
+ const char *cwd;
+ int test;
+ int fail = 0;
+ int i;
+ struct test_case_struct ts;
+
+ if (argc > 1)
+ {
+ command_line_test (argv[1]);
+ return 0;
+ }
+
+ cwd = getcwd (NULL, 0);
+
+ /* Set up arena for pathname expansion */
+ tmpnam (tmpdir);
+ if (mkdir (tmpdir, S_IRWXU) || chdir (tmpdir))
+ return -1;
+ else
+ {
+ int fd;
+
+ for (i = 0; globfile[i]; ++i)
+ if ((fd = creat (globfile[i], S_IRUSR | S_IWUSR)) == -1
+ || close (fd))
+ return -1;
+ }
+
+ for (test = 0; test_case[test].retval != -1; test++)
+ if (testit (&test_case[test]))
+ ++fail;
+
+ /* Tilde-expansion tests. */
+ pw = getpwnam ("root");
+ if (pw != NULL)
+ {
+ ts.retval = 0;
+ ts.env = NULL;
+ ts.words = "~root ";
+ ts.flags = 0;
+ ts.wordc = 1;
+ ts.wordv[0] = pw->pw_dir;
+ ts.ifs = IFS;
+
+ if (testit (&ts))
+ ++fail;
+
+ ts.retval = 0;
+ ts.env = pw->pw_dir;
+ ts.words = "${var#~root}x";
+ ts.flags = 0;
+ ts.wordc = 1;
+ ts.wordv[0] = "x";
+ ts.ifs = IFS;
+
+ if (testit (&ts))
+ ++fail;
+ }
+
+ /* "~" expands to value of $HOME when HOME is set */
+
+ setenv ("HOME", "/dummy/home", 1);
+ ts.retval = 0;
+ ts.env = NULL;
+ ts.words = "~ ~/foo";
+ ts.flags = 0;
+ ts.wordc = 2;
+ ts.wordv[0] = "/dummy/home";
+ ts.wordv[1] = "/dummy/home/foo";
+ ts.ifs = IFS;
+
+ if (testit (&ts))
+ ++fail;
+
+ /* "~" expands to home dir from passwd file if HOME is not set */
+
+ pw = getpwuid (getuid ());
+ if (pw != NULL)
+ {
+ unsetenv ("HOME");
+ ts.retval = 0;
+ ts.env = NULL;
+ ts.words = "~";
+ ts.flags = 0;
+ ts.wordc = 1;
+ ts.wordv[0] = pw->pw_dir;
+ ts.ifs = IFS;
+
+ if (testit (&ts))
+ ++fail;
+ }
+
+ puts ("tests completed, now cleaning up");
+
+ /* Clean up */
+ for (i = 0; globfile[i]; ++i)
+ remove (globfile[i]);
+
+ if (cwd == NULL)
+ cwd = "..";
+
+ chdir (cwd);
+ rmdir (tmpdir);
+
+ printf ("tests failed: %d\n", fail);
+
+ return fail != 0;
+}
+
+
+static int
+testit (struct test_case_struct *tc)
+{
+ int retval;
+ wordexp_t we, sav_we;
+ char *dummy;
+ int bzzzt = 0;
+ int start_offs = 0;
+ int i;
+
+ if (tc->env)
+ setenv ("var", tc->env, 1);
+ else
+ unsetenv ("var");
+
+ if (tc->ifs)
+ setenv ("IFS", tc->ifs, 1);
+ else
+ unsetenv ("IFS");
+
+ sav_we.we_wordc = 99;
+ sav_we.we_wordv = &dummy;
+ sav_we.we_offs = 3;
+ we = sav_we;
+
+ printf ("Test %d (%s): ", ++tests, tc->words);
+
+ if (tc->flags & WRDE_APPEND)
+ {
+ /* initial wordexp() call, to be appended to */
+ if (wordexp ("pre1 pre2", &we, tc->flags & ~WRDE_APPEND) != 0)
+ {
+ printf ("FAILED setup\n");
+ return 1;
+ }
+ }
+ retval = wordexp (tc->words, &we, tc->flags);
+
+ if (tc->flags & WRDE_DOOFFS)
+ start_offs = sav_we.we_offs;
+
+ if (retval != tc->retval || (retval == 0 && we.we_wordc != tc->wordc))
+ bzzzt = 1;
+ else if (retval == 0)
+ {
+ for (i = 0; i < start_offs; ++i)
+ if (we.we_wordv[i] != NULL)
+ {
+ bzzzt = 1;
+ break;
+ }
+
+ for (i = 0; i < we.we_wordc; ++i)
+ if (we.we_wordv[i+start_offs] == NULL ||
+ strcmp (tc->wordv[i], we.we_wordv[i+start_offs]) != 0)
+ {
+ bzzzt = 1;
+ break;
+ }
+ }
+
+ if (bzzzt)
+ {
+ printf ("FAILED\n");
+ printf ("Test words: <%s>, need retval %d, wordc %Zd\n",
+ tc->words, tc->retval, tc->wordc);
+ if (start_offs != 0)
+ printf ("(preceded by %d NULLs)\n", start_offs);
+ printf ("Got retval %d, wordc %Zd: ", retval, we.we_wordc);
+ if (retval == 0 || retval == WRDE_NOSPACE)
+ {
+ for (i = 0; i < we.we_wordc + start_offs; ++i)
+ if (we.we_wordv[i] == NULL)
+ printf ("NULL ");
+ else
+ printf ("<%s> ", we.we_wordv[i]);
+ }
+ printf ("\n");
+ }
+ else if (retval != 0 && retval != WRDE_NOSPACE &&
+ (we.we_wordc != sav_we.we_wordc ||
+ we.we_wordv != sav_we.we_wordv ||
+ we.we_offs != sav_we.we_offs))
+ {
+ bzzzt = 1;
+ printf ("FAILED to restore wordexp_t members\n");
+ }
+ else
+ printf ("OK\n");
+
+ if (retval == 0 || retval == WRDE_NOSPACE)
+ wordfree (&we);
+
+ return bzzzt;
+}
diff --git a/libc/posix/wordexp-tst.sh b/libc/posix/wordexp-tst.sh
new file mode 100755
index 000000000..9654457f5
--- /dev/null
+++ b/libc/posix/wordexp-tst.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+# Some of these tests may look a little weird.
+# The first parameter to wordexp-test is what it gives to wordexp.
+# The others are just there to be parameters.
+
+common_objpfx=$1; shift
+elf_objpfx=$1; shift
+rtld_installed_name=$1; shift
+logfile=${common_objpfx}posix/wordexp-tst.out
+testout=${common_objpfx}posix/wordexp-test-result
+
+result=0
+rm -f $logfile
+# This is written in this funny way so that there is no trailing whitespace.
+# The first line contains a space followed by a tab.
+IFS=" \
+
+"
+export IFS
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '$*' > ${testout}1
+cat <<"EOF" | cmp - ${testout}1 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "$*"
+EOF
+if test $failed -ne 0; then
+ echo '$* test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '${*}' unquoted > ${testout}2
+cat <<"EOF" | cmp - ${testout}2 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "${*}"
+we_wordv[1] = "unquoted"
+EOF
+if test $failed -ne 0; then
+ echo '${*} test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '$@' unquoted > ${testout}3
+cat <<"EOF" | cmp - ${testout}3 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "$@"
+we_wordv[1] = "unquoted"
+EOF
+if test $failed -ne 0; then
+ echo '$@ test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '"$* quoted"' param > ${testout}4
+cat <<"EOF" | cmp - ${testout}4 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = ""$* quoted" param quoted"
+EOF
+if test $failed -ne 0; then
+ echo '$* quoted test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '"$@ quoted"' param > ${testout}5
+cat <<"EOF" | cmp - ${testout}5 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = ""$@ quoted""
+we_wordv[1] = "param quoted"
+EOF
+if test $failed -ne 0; then
+ echo '$@ quoted test failed'
+ status=1
+fi
+# Why? Because bash does it that way..
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '$#' 2 3 4 5 > ${testout}6
+cat <<"EOF" | cmp - ${testout}6 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "5"
+EOF
+if test $failed -ne 0; then
+ echo '$# test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '$2 ${3} $4' 2nd 3rd "4 th" > ${testout}7
+cat <<"EOF" | cmp - ${testout}7 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "2nd"
+we_wordv[1] = "3rd"
+we_wordv[2] = "4"
+we_wordv[3] = "th"
+EOF
+if test $failed -ne 0; then
+ echo '$2 ${3} $4 test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '${11}' 2 3 4 5 6 7 8 9 10 11 > ${testout}8
+cat <<"EOF" | cmp - ${testout}8 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "11"
+EOF
+if test $failed -ne 0; then
+ echo '${11} test failed'
+ status=1
+fi
+
+failed=0
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '"a $@ b"' c d > ${testout}9
+cat <<"EOF" | cmp - ${testout}9 >> $logfile || failed=1
+wordexp returned 0
+we_wordv[0] = "a "a $@ b""
+we_wordv[1] = "c"
+we_wordv[2] = "d b"
+EOF
+if test $failed -ne 0; then
+ echo '"a $@ b" test failed'
+ status=1
+fi
+
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '${#@} ${#2} *$**' two 3 4 > ${testout}10
+cat <<"EOF" | cmp - ${testout}10 || failed=1
+wordexp returned 0
+we_wordv[0] = "4"
+we_wordv[1] = "3"
+we_wordv[2] = "*${#@}"
+we_wordv[3] = "${#2}"
+we_wordv[4] = "*$**"
+we_wordv[5] = "two"
+we_wordv[6] = "3"
+we_wordv[7] = "4*"
+EOF
+
+exit $result
diff --git a/libc/posix/wordexp.c b/libc/posix/wordexp.c
new file mode 100644
index 000000000..adece95ef
--- /dev/null
+++ b/libc/posix/wordexp.c
@@ -0,0 +1,2452 @@
+/* POSIX.2 wordexp implementation.
+ Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <glob.h>
+#include <libintl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+#include <wordexp.h>
+
+#include <bits/libc-lock.h>
+#include <stdio-common/_itoa.h>
+
+/* Undefine the following line for the production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+/* Get some device information. */
+#include <device-nrs.h>
+
+/*
+ * This is a recursive-descent-style word expansion routine.
+ */
+
+/* These variables are defined and initialized in the startup code. */
+extern int __libc_argc attribute_hidden;
+extern char **__libc_argv attribute_hidden;
+
+/* Some forward declarations */
+static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char *ifs,
+ const char *ifs_white, int quoted)
+ internal_function;
+static int parse_backtick (char **word, size_t *word_length,
+ size_t *max_length, const char *words,
+ size_t *offset, int flags, wordexp_t *pwordexp,
+ const char *ifs, const char *ifs_white)
+ internal_function;
+static int parse_dquote (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char *ifs,
+ const char *ifs_white)
+ internal_function;
+static int eval_expr (char *expr, long int *result) internal_function;
+
+/* The w_*() functions manipulate word lists. */
+
+#define W_CHUNK (100)
+
+/* Result of w_newword will be ignored if it's the last word. */
+static inline char *
+w_newword (size_t *actlen, size_t *maxlen)
+{
+ *actlen = *maxlen = 0;
+ return NULL;
+}
+
+static char *
+w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
+ /* (lengths exclude trailing zero) */
+{
+ /* Add a character to the buffer, allocating room for it if needed. */
+
+ if (*actlen == *maxlen)
+ {
+ char *old_buffer = buffer;
+ assert (buffer == NULL || *maxlen != 0);
+ *maxlen += W_CHUNK;
+ buffer = (char *) realloc (buffer, 1 + *maxlen);
+
+ if (buffer == NULL)
+ free (old_buffer);
+ }
+
+ if (buffer != NULL)
+ {
+ buffer[*actlen] = ch;
+ buffer[++(*actlen)] = '\0';
+ }
+
+ return buffer;
+}
+
+static char *
+internal_function
+w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
+ size_t len)
+{
+ /* Add a string to the buffer, allocating room for it if needed.
+ */
+ if (*actlen + len > *maxlen)
+ {
+ char *old_buffer = buffer;
+ assert (buffer == NULL || *maxlen != 0);
+ *maxlen += MAX (2 * len, W_CHUNK);
+ buffer = realloc (old_buffer, 1 + *maxlen);
+
+ if (buffer == NULL)
+ free (old_buffer);
+ }
+
+ if (buffer != NULL)
+ {
+ *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
+ *actlen += len;
+ }
+
+ return buffer;
+}
+
+static char *
+internal_function
+w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
+ /* (lengths exclude trailing zero) */
+{
+ /* Add a string to the buffer, allocating room for it if needed.
+ */
+ size_t len;
+
+ assert (str != NULL); /* w_addstr only called from this file */
+ len = strlen (str);
+
+ return w_addmem (buffer, actlen, maxlen, str, len);
+}
+
+static int
+internal_function
+w_addword (wordexp_t *pwordexp, char *word)
+{
+ /* Add a word to the wordlist */
+ size_t num_p;
+ char **new_wordv;
+ bool allocated = false;
+
+ /* Internally, NULL acts like "". Convert NULLs to "" before
+ * the caller sees them.
+ */
+ if (word == NULL)
+ {
+ word = __strdup ("");
+ if (word == NULL)
+ goto no_space;
+ allocated = true;
+ }
+
+ num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
+ new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
+ if (new_wordv != NULL)
+ {
+ pwordexp->we_wordv = new_wordv;
+ pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
+ pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
+ return 0;
+ }
+
+ if (allocated)
+ free (word);
+
+no_space:
+ return WRDE_NOSPACE;
+}
+
+/* The parse_*() functions should leave *offset being the offset in 'words'
+ * to the last character processed.
+ */
+
+static int
+internal_function
+parse_backslash (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset)
+{
+ /* We are poised _at_ a backslash, not in quotes */
+
+ switch (words[1 + *offset])
+ {
+ case 0:
+ /* Backslash is last character of input words */
+ return WRDE_SYNTAX;
+
+ case '\n':
+ ++(*offset);
+ break;
+
+ default:
+ *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+internal_function
+parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset)
+{
+ /* We are poised _at_ a backslash, inside quotes */
+
+ switch (words[1 + *offset])
+ {
+ case 0:
+ /* Backslash is last character of input words */
+ return WRDE_SYNTAX;
+
+ case '\n':
+ ++(*offset);
+ break;
+
+ case '$':
+ case '`':
+ case '"':
+ case '\\':
+ *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+
+ default:
+ *word = w_addchar (*word, word_length, max_length, words[*offset]);
+ if (*word != NULL)
+ *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
+
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+internal_function
+parse_tilde (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, size_t wordc)
+{
+ /* We are poised _at_ a tilde */
+ size_t i;
+
+ if (*word_length != 0)
+ {
+ if (!((*word)[*word_length - 1] == '=' && wordc == 0))
+ {
+ if (!((*word)[*word_length - 1] == ':'
+ && strchr (*word, '=') && wordc == 0))
+ {
+ *word = w_addchar (*word, word_length, max_length, '~');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+ }
+
+ for (i = 1 + *offset; words[i]; i++)
+ {
+ if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
+ words[i] == '\t' || words[i] == 0 )
+ break;
+
+ if (words[i] == '\\')
+ {
+ *word = w_addchar (*word, word_length, max_length, '~');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+
+ if (i == 1 + *offset)
+ {
+ /* Tilde appears on its own */
+ uid_t uid;
+ struct passwd pwd, *tpwd;
+ int buflen = 1000;
+ char* home;
+ char* buffer;
+ int result;
+
+ /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
+ results are unspecified. We do a lookup on the uid if
+ HOME is unset. */
+
+ home = getenv ("HOME");
+ if (home != NULL)
+ {
+ *word = w_addstr (*word, word_length, max_length, home);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ else
+ {
+ uid = __getuid ();
+ buffer = __alloca (buflen);
+
+ while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
+ && errno == ERANGE)
+ buffer = extend_alloca (buffer, buflen, buflen + 1000);
+
+ if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
+ {
+ *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ else
+ {
+ *word = w_addchar (*word, word_length, max_length, '~');
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+ }
+ else
+ {
+ /* Look up user name in database to get home directory */
+ char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
+ struct passwd pwd, *tpwd;
+ int buflen = 1000;
+ char* buffer = __alloca (buflen);
+ int result;
+
+ while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
+ && errno == ERANGE)
+ buffer = extend_alloca (buffer, buflen, buflen + 1000);
+
+ if (result == 0 && tpwd != NULL && pwd.pw_dir)
+ *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
+ else
+ {
+ /* (invalid login name) */
+ *word = w_addchar (*word, word_length, max_length, '~');
+ if (*word != NULL)
+ *word = w_addstr (*word, word_length, max_length, user);
+ }
+
+ *offset = i - 1;
+ }
+ return *word ? 0 : WRDE_NOSPACE;
+}
+
+
+static int
+internal_function
+do_parse_glob (const char *glob_word, char **word, size_t *word_length,
+ size_t *max_length, wordexp_t *pwordexp, const char *ifs,
+ const char *ifs_white)
+{
+ int error;
+ unsigned int match;
+ glob_t globbuf;
+
+ error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf);
+
+ if (error != 0)
+ {
+ /* We can only run into memory problems. */
+ assert (error == GLOB_NOSPACE);
+ return WRDE_NOSPACE;
+ }
+
+ if (ifs && !*ifs)
+ {
+ /* No field splitting allowed. */
+ assert (globbuf.gl_pathv[0] != NULL);
+ *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]);
+ for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
+ {
+ *word = w_addchar (*word, word_length, max_length, ' ');
+ if (*word != NULL)
+ *word = w_addstr (*word, word_length, max_length,
+ globbuf.gl_pathv[match]);
+ }
+
+ globfree (&globbuf);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ assert (ifs == NULL || *ifs != '\0');
+ if (*word != NULL)
+ {
+ free (*word);
+ *word = w_newword (word_length, max_length);
+ }
+
+ for (match = 0; match < globbuf.gl_pathc; ++match)
+ {
+ char *matching_word = __strdup (globbuf.gl_pathv[match]);
+ if (matching_word == NULL || w_addword (pwordexp, matching_word))
+ {
+ globfree (&globbuf);
+ return WRDE_NOSPACE;
+ }
+ }
+
+ globfree (&globbuf);
+ return 0;
+}
+
+static int
+internal_function
+parse_glob (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after a '*', a '[' or a '?'. */
+ int error = WRDE_NOSPACE;
+ int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
+ size_t i;
+ wordexp_t glob_list; /* List of words to glob */
+
+ glob_list.we_wordc = 0;
+ glob_list.we_wordv = NULL;
+ glob_list.we_offs = 0;
+ for (; words[*offset] != '\0'; ++*offset)
+ {
+ if (strchr (ifs, words[*offset]) != NULL)
+ /* Reached IFS */
+ break;
+
+ /* Sort out quoting */
+ if (words[*offset] == '\'')
+ {
+ if (quoted == 0)
+ {
+ quoted = 1;
+ continue;
+ }
+ else if (quoted == 1)
+ {
+ quoted = 0;
+ continue;
+ }
+ }
+ else if (words[*offset] == '"')
+ {
+ if (quoted == 0)
+ {
+ quoted = 2;
+ continue;
+ }
+ else if (quoted == 2)
+ {
+ quoted = 0;
+ continue;
+ }
+ }
+
+ /* Sort out other special characters */
+ if (quoted != 1 && words[*offset] == '$')
+ {
+ error = parse_dollars (word, word_length, max_length, words,
+ offset, flags, &glob_list, ifs, ifs_white,
+ quoted == 2);
+ if (error)
+ goto tidy_up;
+
+ continue;
+ }
+ else if (words[*offset] == '\\')
+ {
+ if (quoted)
+ error = parse_qtd_backslash (word, word_length, max_length,
+ words, offset);
+ else
+ error = parse_backslash (word, word_length, max_length,
+ words, offset);
+
+ if (error)
+ goto tidy_up;
+
+ continue;
+ }
+
+ *word = w_addchar (*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ goto tidy_up;
+ }
+
+ /* Don't forget to re-parse the character we stopped at. */
+ --*offset;
+
+ /* Glob the words */
+ error = w_addword (&glob_list, *word);
+ *word = w_newword (word_length, max_length);
+ for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
+ error = do_parse_glob (glob_list.we_wordv[i], word, word_length,
+ max_length, pwordexp, ifs, ifs_white);
+
+ /* Now tidy up */
+tidy_up:
+ wordfree (&glob_list);
+ return error;
+}
+
+static int
+internal_function
+parse_squote (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset)
+{
+ /* We are poised just after a single quote */
+ for (; words[*offset]; ++(*offset))
+ {
+ if (words[*offset] != '\'')
+ {
+ *word = w_addchar (*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ else return 0;
+ }
+
+ /* Unterminated string */
+ return WRDE_SYNTAX;
+}
+
+/* Functions to evaluate an arithmetic expression */
+static int
+internal_function
+eval_expr_val (char **expr, long int *result)
+{
+ char *digit;
+
+ /* Skip white space */
+ for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
+
+ if (*digit == '(')
+ {
+ /* Scan for closing paren */
+ for (++digit; **expr && **expr != ')'; ++(*expr));
+
+ /* Is there one? */
+ if (!**expr)
+ return WRDE_SYNTAX;
+
+ *(*expr)++ = 0;
+
+ if (eval_expr (digit, result))
+ return WRDE_SYNTAX;
+
+ return 0;
+ }
+
+ /* POSIX requires that decimal, octal, and hexadecimal constants are
+ recognized. Therefore we pass 0 as the third parameter to strtol. */
+ *result = strtol (digit, expr, 0);
+ if (digit == *expr)
+ return WRDE_SYNTAX;
+
+ return 0;
+}
+
+static int
+internal_function
+eval_expr_multdiv (char **expr, long int *result)
+{
+ long int arg;
+
+ /* Read a Value */
+ if (eval_expr_val (expr, result) != 0)
+ return WRDE_SYNTAX;
+
+ while (**expr)
+ {
+ /* Skip white space */
+ for (; *expr && **expr && isspace (**expr); ++(*expr));
+
+ if (**expr == '*')
+ {
+ ++(*expr);
+ if (eval_expr_val (expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result *= arg;
+ }
+ else if (**expr == '/')
+ {
+ ++(*expr);
+ if (eval_expr_val (expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result /= arg;
+ }
+ else break;
+ }
+
+ return 0;
+}
+
+static int
+internal_function
+eval_expr (char *expr, long int *result)
+{
+ long int arg;
+
+ /* Read a Multdiv */
+ if (eval_expr_multdiv (&expr, result) != 0)
+ return WRDE_SYNTAX;
+
+ while (*expr)
+ {
+ /* Skip white space */
+ for (; expr && *expr && isspace (*expr); ++expr);
+
+ if (*expr == '+')
+ {
+ ++expr;
+ if (eval_expr_multdiv (&expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result += arg;
+ }
+ else if (*expr == '-')
+ {
+ ++expr;
+ if (eval_expr_multdiv (&expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result -= arg;
+ }
+ else break;
+ }
+
+ return 0;
+}
+
+static int
+internal_function
+parse_arith (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags, int bracket)
+{
+ /* We are poised just after "$((" or "$[" */
+ int error;
+ int paren_depth = 1;
+ size_t expr_length;
+ size_t expr_maxlen;
+ char *expr;
+
+ expr = w_newword (&expr_length, &expr_maxlen);
+ for (; words[*offset]; ++(*offset))
+ {
+ switch (words[*offset])
+ {
+ case '$':
+ error = parse_dollars (&expr, &expr_length, &expr_maxlen,
+ words, offset, flags, NULL, NULL, NULL, 1);
+ /* The ``1'' here is to tell parse_dollars not to
+ * split the fields.
+ */
+ if (error)
+ {
+ free (expr);
+ return error;
+ }
+ break;
+
+ case '`':
+ (*offset)++;
+ error = parse_backtick (&expr, &expr_length, &expr_maxlen,
+ words, offset, flags, NULL, NULL, NULL);
+ /* The first NULL here is to tell parse_backtick not to
+ * split the fields.
+ */
+ if (error)
+ {
+ free (expr);
+ return error;
+ }
+ break;
+
+ case '\\':
+ error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
+ words, offset);
+ if (error)
+ {
+ free (expr);
+ return error;
+ }
+ /* I think that a backslash within an
+ * arithmetic expansion is bound to
+ * cause an error sooner or later anyway though.
+ */
+ break;
+
+ case ')':
+ if (--paren_depth == 0)
+ {
+ char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
+ long int numresult = 0;
+ long long int convertme;
+
+ if (bracket || words[1 + *offset] != ')')
+ {
+ free (expr);
+ return WRDE_SYNTAX;
+ }
+
+ ++(*offset);
+
+ /* Go - evaluate. */
+ if (*expr && eval_expr (expr, &numresult) != 0)
+ {
+ free (expr);
+ return WRDE_SYNTAX;
+ }
+
+ if (numresult < 0)
+ {
+ convertme = -numresult;
+ *word = w_addchar (*word, word_length, max_length, '-');
+ if (!*word)
+ {
+ free (expr);
+ return WRDE_NOSPACE;
+ }
+ }
+ else
+ convertme = numresult;
+
+ result[20] = '\0';
+ *word = w_addstr (*word, word_length, max_length,
+ _itoa (convertme, &result[20], 10, 0));
+ free (expr);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
+ if (expr == NULL)
+ return WRDE_NOSPACE;
+
+ break;
+
+ case ']':
+ if (bracket && paren_depth == 1)
+ {
+ char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
+ long int numresult = 0;
+
+ /* Go - evaluate. */
+ if (*expr && eval_expr (expr, &numresult) != 0)
+ {
+ free (expr);
+ return WRDE_SYNTAX;
+ }
+
+ result[20] = '\0';
+ *word = w_addstr (*word, word_length, max_length,
+ _itoa_word (numresult, &result[20], 10, 0));
+ free (expr);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ free (expr);
+ return WRDE_SYNTAX;
+
+ case '\n':
+ case ';':
+ case '{':
+ case '}':
+ free (expr);
+ return WRDE_BADCHAR;
+
+ case '(':
+ ++paren_depth;
+ default:
+ expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
+ if (expr == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Premature end */
+ free (expr);
+ return WRDE_SYNTAX;
+}
+
+/* Function called by child process in exec_comm() */
+static inline void
+internal_function __attribute__ ((always_inline))
+exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
+{
+ const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
+
+ /* Execute the command, or just check syntax? */
+ if (noexec)
+ args[1] = "-nc";
+
+ /* Redirect output. */
+ __dup2 (fildes[1], STDOUT_FILENO);
+ __close (fildes[1]);
+
+ /* Redirect stderr to /dev/null if we have to. */
+ if (showerr == 0)
+ {
+ struct stat64 st;
+ int fd;
+ __close (2);
+ fd = __open (_PATH_DEVNULL, O_WRONLY);
+ if (fd >= 0 && fd != 2)
+ {
+ __dup2 (fd, STDERR_FILENO);
+ __close (fd);
+ }
+ /* Be paranoid. Check that we actually opened the /dev/null
+ device. */
+ if (__builtin_expect (__fxstat64 (_STAT_VER, STDERR_FILENO, &st), 0) != 0
+ || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0
+#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
+ || st.st_rdev != makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
+#endif
+ )
+ /* It's not the /dev/null device. Stop right here. The
+ problem is: how do we stop? We use _exit() with an
+ hopefully unusual exit code. */
+ _exit (90);
+ }
+
+ /* Make sure the subshell doesn't field-split on our behalf. */
+ __unsetenv ("IFS");
+
+ __close (fildes[0]);
+ __execve (_PATH_BSHELL, (char *const *) args, __environ);
+
+ /* Bad. What now? */
+ abort ();
+}
+
+/* Function to execute a command and retrieve the results */
+/* pwordexp contains NULL if field-splitting is forbidden */
+static int
+internal_function
+exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
+ int flags, wordexp_t *pwordexp, const char *ifs,
+ const char *ifs_white)
+{
+ int fildes[2];
+#define bufsize 128
+ int buflen;
+ int i;
+ int status = 0;
+ size_t maxnewlines = 0;
+ char buffer[bufsize];
+ pid_t pid;
+ int noexec = 0;
+
+ /* Don't fork() unless necessary */
+ if (!comm || !*comm)
+ return 0;
+
+ if (__pipe (fildes))
+ /* Bad */
+ return WRDE_NOSPACE;
+
+ again:
+ if ((pid = __fork ()) < 0)
+ {
+ /* Bad */
+ if (fildes[0] != -1)
+ __close (fildes[0]);
+ if (fildes[1] != -1)
+ __close (fildes[1]);
+ return WRDE_NOSPACE;
+ }
+
+ if (pid == 0)
+ exec_comm_child (comm, fildes, noexec ? 0 : flags & WRDE_SHOWERR, noexec);
+
+ /* Parent */
+
+ /* If we are just testing the syntax, only wait. */
+ if (noexec)
+ return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid
+ && status != 0) ? WRDE_SYNTAX : 0;
+
+ __close (fildes[1]);
+ fildes[1] = -1;
+
+ if (!pwordexp)
+ /* Quoted - no field splitting */
+ {
+ while (1)
+ {
+ if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
+ bufsize))) < 1)
+ {
+ if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0)
+ continue;
+ if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
+ bufsize))) < 1)
+ break;
+ }
+
+ maxnewlines += buflen;
+
+ *word = w_addmem (*word, word_length, max_length, buffer, buflen);
+ if (*word == NULL)
+ goto no_space;
+ }
+ }
+ else
+ /* Not quoted - split fields */
+ {
+ int copying = 0;
+ /* 'copying' is:
+ * 0 when searching for first character in a field not IFS white space
+ * 1 when copying the text of a field
+ * 2 when searching for possible non-whitespace IFS
+ * 3 when searching for non-newline after copying field
+ */
+
+ while (1)
+ {
+ if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
+ bufsize))) < 1)
+ {
+ if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0)
+ continue;
+ if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
+ bufsize))) < 1)
+ break;
+ }
+
+ for (i = 0; i < buflen; ++i)
+ {
+ if (strchr (ifs, buffer[i]) != NULL)
+ {
+ /* Current character is IFS */
+ if (strchr (ifs_white, buffer[i]) == NULL)
+ {
+ /* Current character is IFS but not whitespace */
+ if (copying == 2)
+ {
+ /* current character
+ * |
+ * V
+ * eg: text<space><comma><space>moretext
+ *
+ * So, strip whitespace IFS (like at the start)
+ */
+ copying = 0;
+ continue;
+ }
+
+ copying = 0;
+ /* fall through and delimit field.. */
+ }
+ else
+ {
+ if (buffer[i] == '\n')
+ {
+ /* Current character is (IFS) newline */
+
+ /* If copying a field, this is the end of it,
+ but maybe all that's left is trailing newlines.
+ So start searching for a non-newline. */
+ if (copying == 1)
+ copying = 3;
+
+ continue;
+ }
+ else
+ {
+ /* Current character is IFS white space, but
+ not a newline */
+
+ /* If not either copying a field or searching
+ for non-newline after a field, ignore it */
+ if (copying != 1 && copying != 3)
+ continue;
+
+ /* End of field (search for non-ws IFS afterwards) */
+ copying = 2;
+ }
+ }
+
+ /* First IFS white space (non-newline), or IFS non-whitespace.
+ * Delimit the field. Nulls are converted by w_addword. */
+ if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
+ goto no_space;
+
+ *word = w_newword (word_length, max_length);
+
+ maxnewlines = 0;
+ /* fall back round the loop.. */
+ }
+ else
+ {
+ /* Not IFS character */
+
+ if (copying == 3)
+ {
+ /* Nothing but (IFS) newlines since the last field,
+ so delimit it here before starting new word */
+ if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
+ goto no_space;
+
+ *word = w_newword (word_length, max_length);
+ }
+
+ copying = 1;
+
+ if (buffer[i] == '\n') /* happens if newline not in IFS */
+ maxnewlines++;
+ else
+ maxnewlines = 0;
+
+ *word = w_addchar (*word, word_length, max_length,
+ buffer[i]);
+ if (*word == NULL)
+ goto no_space;
+ }
+ }
+ }
+ }
+
+ /* Chop off trailing newlines (required by POSIX.2) */
+ /* Ensure we don't go back further than the beginning of the
+ substitution (i.e. remove maxnewlines bytes at most) */
+ while (maxnewlines-- != 0 &&
+ *word_length > 0 && (*word)[*word_length - 1] == '\n')
+ {
+ (*word)[--*word_length] = '\0';
+
+ /* If the last word was entirely newlines, turn it into a new word
+ * which can be ignored if there's nothing following it. */
+ if (*word_length == 0)
+ {
+ free (*word);
+ *word = w_newword (word_length, max_length);
+ break;
+ }
+ }
+
+ __close (fildes[0]);
+ fildes[0] = -1;
+
+ /* Check for syntax error (re-execute but with "-n" flag) */
+ if (buflen < 1 && status != 0)
+ {
+ noexec = 1;
+ goto again;
+ }
+
+ return 0;
+
+no_space:
+ __kill (pid, SIGKILL);
+ TEMP_FAILURE_RETRY (__waitpid (pid, NULL, 0));
+ __close (fildes[0]);
+ return WRDE_NOSPACE;
+}
+
+static int
+internal_function
+parse_comm (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
+ const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after "$(" */
+ int paren_depth = 1;
+ int error = 0;
+ int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
+ size_t comm_length;
+ size_t comm_maxlen;
+ char *comm = w_newword (&comm_length, &comm_maxlen);
+
+ for (; words[*offset]; ++(*offset))
+ {
+ switch (words[*offset])
+ {
+ case '\'':
+ if (quoted == 0)
+ quoted = 1;
+ else if (quoted == 1)
+ quoted = 0;
+
+ break;
+
+ case '"':
+ if (quoted == 0)
+ quoted = 2;
+ else if (quoted == 2)
+ quoted = 0;
+
+ break;
+
+ case ')':
+ if (!quoted && --paren_depth == 0)
+ {
+ /* Go -- give script to the shell */
+ if (comm)
+ {
+#ifdef __libc_ptf_call
+ /* We do not want the exec_comm call to be cut short
+ by a thread cancellation since cleanup is very
+ ugly. Therefore disable cancellation for
+ now. */
+ // XXX Ideally we do want the thread being cancelable.
+ // XXX If demand is there we'll change it.
+ int state = PTHREAD_CANCEL_ENABLE;
+ __libc_ptf_call (pthread_setcancelstate,
+ (PTHREAD_CANCEL_DISABLE, &state), 0);
+#endif
+
+ error = exec_comm (comm, word, word_length, max_length,
+ flags, pwordexp, ifs, ifs_white);
+
+#ifdef __libc_ptf_call
+ __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+#endif
+
+ free (comm);
+ }
+
+ return error;
+ }
+
+ /* This is just part of the script */
+ break;
+
+ case '(':
+ if (!quoted)
+ ++paren_depth;
+ }
+
+ comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
+ if (comm == NULL)
+ return WRDE_NOSPACE;
+ }
+
+ /* Premature end. */
+ free (comm);
+
+ return WRDE_SYNTAX;
+}
+
+static int
+internal_function
+parse_param (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
+ const char *ifs, const char *ifs_white, int quoted)
+{
+ /* We are poised just after "$" */
+ enum action
+ {
+ ACT_NONE,
+ ACT_RP_SHORT_LEFT = '#',
+ ACT_RP_LONG_LEFT = 'L',
+ ACT_RP_SHORT_RIGHT = '%',
+ ACT_RP_LONG_RIGHT = 'R',
+ ACT_NULL_ERROR = '?',
+ ACT_NULL_SUBST = '-',
+ ACT_NONNULL_SUBST = '+',
+ ACT_NULL_ASSIGN = '='
+ };
+ size_t env_length;
+ size_t env_maxlen;
+ size_t pat_length;
+ size_t pat_maxlen;
+ size_t start = *offset;
+ char *env;
+ char *pattern;
+ char *value = NULL;
+ enum action action = ACT_NONE;
+ int depth = 0;
+ int colon_seen = 0;
+ int seen_hash = 0;
+ int free_value = 0;
+ int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
+ int error;
+ int special = 0;
+ char buffer[21];
+ int brace = words[*offset] == '{';
+
+ env = w_newword (&env_length, &env_maxlen);
+ pattern = w_newword (&pat_length, &pat_maxlen);
+
+ if (brace)
+ ++*offset;
+
+ /* First collect the parameter name. */
+
+ if (words[*offset] == '#')
+ {
+ seen_hash = 1;
+ if (!brace)
+ goto envsubst;
+ ++*offset;
+ }
+
+ if (isalpha (words[*offset]) || words[*offset] == '_')
+ {
+ /* Normal parameter name. */
+ do
+ {
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ }
+ while (isalnum (words[++*offset]) || words[*offset] == '_');
+ }
+ else if (isdigit (words[*offset]))
+ {
+ /* Numeric parameter name. */
+ special = 1;
+ do
+ {
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ if (!brace)
+ goto envsubst;
+ }
+ while (isdigit(words[++*offset]));
+ }
+ else if (strchr ("*@$", words[*offset]) != NULL)
+ {
+ /* Special parameter. */
+ special = 1;
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ ++*offset;
+ }
+ else
+ {
+ if (brace)
+ goto syntax;
+ }
+
+ if (brace)
+ {
+ /* Check for special action to be applied to the value. */
+ switch (words[*offset])
+ {
+ case '}':
+ /* Evaluate. */
+ goto envsubst;
+
+ case '#':
+ action = ACT_RP_SHORT_LEFT;
+ if (words[1 + *offset] == '#')
+ {
+ ++*offset;
+ action = ACT_RP_LONG_LEFT;
+ }
+ break;
+
+ case '%':
+ action = ACT_RP_SHORT_RIGHT;
+ if (words[1 + *offset] == '%')
+ {
+ ++*offset;
+ action = ACT_RP_LONG_RIGHT;
+ }
+ break;
+
+ case ':':
+ if (strchr ("-=?+", words[1 + *offset]) == NULL)
+ goto syntax;
+
+ colon_seen = 1;
+ action = words[++*offset];
+ break;
+
+ case '-':
+ case '=':
+ case '?':
+ case '+':
+ action = words[*offset];
+ break;
+
+ default:
+ goto syntax;
+ }
+
+ /* Now collect the pattern, but don't expand it yet. */
+ ++*offset;
+ for (; words[*offset]; ++(*offset))
+ {
+ switch (words[*offset])
+ {
+ case '{':
+ if (!pattern_is_quoted)
+ ++depth;
+ break;
+
+ case '}':
+ if (!pattern_is_quoted)
+ {
+ if (depth == 0)
+ goto envsubst;
+ --depth;
+ }
+ break;
+
+ case '\\':
+ if (pattern_is_quoted)
+ /* Quoted; treat as normal character. */
+ break;
+
+ /* Otherwise, it's an escape: next character is literal. */
+ if (words[++*offset] == '\0')
+ goto syntax;
+
+ pattern = w_addchar (pattern, &pat_length, &pat_maxlen, '\\');
+ if (pattern == NULL)
+ goto no_space;
+
+ break;
+
+ case '\'':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 1;
+ else if (pattern_is_quoted == 1)
+ pattern_is_quoted = 0;
+
+ break;
+
+ case '"':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 2;
+ else if (pattern_is_quoted == 2)
+ pattern_is_quoted = 0;
+
+ break;
+ }
+
+ pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
+ words[*offset]);
+ if (pattern == NULL)
+ goto no_space;
+ }
+ }
+
+ /* End of input string -- remember to reparse the character that we
+ * stopped at. */
+ --(*offset);
+
+envsubst:
+ if (words[start] == '{' && words[*offset] != '}')
+ goto syntax;
+
+ if (env == NULL)
+ {
+ if (seen_hash)
+ {
+ /* $# expands to the number of positional parameters */
+ buffer[20] = '\0';
+ value = _itoa_word (__libc_argc - 1, &buffer[20], 10, 0);
+ seen_hash = 0;
+ }
+ else
+ {
+ /* Just $ on its own */
+ *offset = start - 1;
+ *word = w_addchar (*word, word_length, max_length, '$');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+ /* Is it a numeric parameter? */
+ else if (isdigit (env[0]))
+ {
+ int n = atoi (env);
+
+ if (n >= __libc_argc)
+ /* Substitute NULL. */
+ value = NULL;
+ else
+ /* Replace with appropriate positional parameter. */
+ value = __libc_argv[n];
+ }
+ /* Is it a special parameter? */
+ else if (special)
+ {
+ /* Is it `$$'? */
+ if (*env == '$')
+ {
+ buffer[20] = '\0';
+ value = _itoa_word (__getpid (), &buffer[20], 10, 0);
+ }
+ /* Is it `${#*}' or `${#@}'? */
+ else if ((*env == '*' || *env == '@') && seen_hash)
+ {
+ buffer[20] = '\0';
+ value = _itoa_word (__libc_argc > 0 ? __libc_argc - 1 : 0,
+ &buffer[20], 10, 0);
+ *word = w_addstr (*word, word_length, max_length, value);
+ free (env);
+ free (pattern);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ /* Is it `$*' or `$@' (unquoted) ? */
+ else if (*env == '*' || (*env == '@' && !quoted))
+ {
+ size_t plist_len = 0;
+ int p;
+ char *end;
+
+ /* Build up value parameter by parameter (copy them) */
+ for (p = 1; __libc_argv[p]; ++p)
+ plist_len += strlen (__libc_argv[p]) + 1; /* for space */
+ value = malloc (plist_len);
+ if (value == NULL)
+ goto no_space;
+ end = value;
+ *end = 0;
+ for (p = 1; __libc_argv[p]; ++p)
+ {
+ if (p > 1)
+ *end++ = ' ';
+ end = __stpcpy (end, __libc_argv[p]);
+ }
+
+ free_value = 1;
+ }
+ else
+ {
+ /* Must be a quoted `$@' */
+ assert (*env == '@' && quoted);
+
+ /* Each parameter is a separate word ("$@") */
+ if (__libc_argc == 2)
+ value = __libc_argv[1];
+ else if (__libc_argc > 2)
+ {
+ int p;
+
+ /* Append first parameter to current word. */
+ value = w_addstr (*word, word_length, max_length,
+ __libc_argv[1]);
+ if (value == NULL || w_addword (pwordexp, value))
+ goto no_space;
+
+ for (p = 2; __libc_argv[p + 1]; p++)
+ {
+ char *newword = __strdup (__libc_argv[p]);
+ if (newword == NULL || w_addword (pwordexp, newword))
+ goto no_space;
+ }
+
+ /* Start a new word with the last parameter. */
+ *word = w_newword (word_length, max_length);
+ value = __libc_argv[p];
+ }
+ else
+ {
+ free (env);
+ free (pattern);
+ return 0;
+ }
+ }
+ }
+ else
+ value = getenv (env);
+
+ if (value == NULL && (flags & WRDE_UNDEF))
+ {
+ /* Variable not defined. */
+ error = WRDE_BADVAL;
+ goto do_error;
+ }
+
+ if (action != ACT_NONE)
+ {
+ int expand_pattern = 0;
+
+ /* First, find out if we need to expand pattern (i.e. if we will
+ * use it). */
+ switch (action)
+ {
+ case ACT_RP_SHORT_LEFT:
+ case ACT_RP_LONG_LEFT:
+ case ACT_RP_SHORT_RIGHT:
+ case ACT_RP_LONG_RIGHT:
+ /* Always expand for these. */
+ expand_pattern = 1;
+ break;
+
+ case ACT_NULL_ERROR:
+ case ACT_NULL_SUBST:
+ case ACT_NULL_ASSIGN:
+ if (!value || (!*value && colon_seen))
+ /* If param is unset, or set but null and a colon has been seen,
+ the expansion of the pattern will be needed. */
+ expand_pattern = 1;
+
+ break;
+
+ case ACT_NONNULL_SUBST:
+ /* Expansion of word will be needed if parameter is set and not null,
+ or set null but no colon has been seen. */
+ if (value && (*value || !colon_seen))
+ expand_pattern = 1;
+
+ break;
+
+ default:
+ assert (! "Unrecognised action!");
+ }
+
+ if (expand_pattern)
+ {
+ /* We need to perform tilde expansion, parameter expansion,
+ command substitution, and arithmetic expansion. We also
+ have to be a bit careful with wildcard characters, as
+ pattern might be given to fnmatch soon. To do this, we
+ convert quotes to escapes. */
+
+ char *expanded;
+ size_t exp_len;
+ size_t exp_maxl;
+ char *p;
+ int quoted = 0; /* 1: single quotes; 2: double */
+
+ expanded = w_newword (&exp_len, &exp_maxl);
+ for (p = pattern; p && *p; p++)
+ {
+ size_t offset;
+
+ switch (*p)
+ {
+ case '"':
+ if (quoted == 2)
+ quoted = 0;
+ else if (quoted == 0)
+ quoted = 2;
+ else break;
+
+ continue;
+
+ case '\'':
+ if (quoted == 1)
+ quoted = 0;
+ else if (quoted == 0)
+ quoted = 1;
+ else break;
+
+ continue;
+
+ case '*':
+ case '?':
+ if (quoted)
+ {
+ /* Convert quoted wildchar to escaped wildchar. */
+ expanded = w_addchar (expanded, &exp_len,
+ &exp_maxl, '\\');
+
+ if (expanded == NULL)
+ goto no_space;
+ }
+ break;
+
+ case '$':
+ offset = 0;
+ error = parse_dollars (&expanded, &exp_len, &exp_maxl, p,
+ &offset, flags, NULL, NULL, NULL, 1);
+ if (error)
+ {
+ if (free_value)
+ free (value);
+
+ free (expanded);
+
+ goto do_error;
+ }
+
+ p += offset;
+ continue;
+
+ case '~':
+ if (quoted || exp_len)
+ break;
+
+ offset = 0;
+ error = parse_tilde (&expanded, &exp_len, &exp_maxl, p,
+ &offset, 0);
+ if (error)
+ {
+ if (free_value)
+ free (value);
+
+ free (expanded);
+
+ goto do_error;
+ }
+
+ p += offset;
+ continue;
+
+ case '\\':
+ expanded = w_addchar (expanded, &exp_len, &exp_maxl, '\\');
+ ++p;
+ assert (*p); /* checked when extracted initially */
+ if (expanded == NULL)
+ goto no_space;
+ }
+
+ expanded = w_addchar (expanded, &exp_len, &exp_maxl, *p);
+
+ if (expanded == NULL)
+ goto no_space;
+ }
+
+ free (pattern);
+
+ pattern = expanded;
+ }
+
+ switch (action)
+ {
+ case ACT_RP_SHORT_LEFT:
+ case ACT_RP_LONG_LEFT:
+ case ACT_RP_SHORT_RIGHT:
+ case ACT_RP_LONG_RIGHT:
+ {
+ char *p;
+ char c;
+ char *end;
+
+ if (value == NULL || pattern == NULL || *pattern == '\0')
+ break;
+
+ end = value + strlen (value);
+
+ switch (action)
+ {
+ case ACT_RP_SHORT_LEFT:
+ for (p = value; p <= end; ++p)
+ {
+ c = *p;
+ *p = '\0';
+ if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
+ {
+ *p = c;
+ if (free_value)
+ {
+ char *newval = __strdup (p);
+ if (newval == NULL)
+ {
+ free (value);
+ goto no_space;
+ }
+ free (value);
+ value = newval;
+ }
+ else
+ value = p;
+ break;
+ }
+ *p = c;
+ }
+
+ break;
+
+ case ACT_RP_LONG_LEFT:
+ for (p = end; p >= value; --p)
+ {
+ c = *p;
+ *p = '\0';
+ if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
+ {
+ *p = c;
+ if (free_value)
+ {
+ char *newval = __strdup (p);
+ if (newval == NULL)
+ {
+ free (value);
+ goto no_space;
+ }
+ free (value);
+ value = newval;
+ }
+ else
+ value = p;
+ break;
+ }
+ *p = c;
+ }
+
+ break;
+
+ case ACT_RP_SHORT_RIGHT:
+ for (p = end; p >= value; --p)
+ {
+ if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
+ {
+ char *newval;
+ newval = malloc (p - value + 1);
+
+ if (newval == NULL)
+ {
+ if (free_value)
+ free (value);
+ goto no_space;
+ }
+
+ *(char *) __mempcpy (newval, value, p - value) = '\0';
+ if (free_value)
+ free (value);
+ value = newval;
+ free_value = 1;
+ break;
+ }
+ }
+
+ break;
+
+ case ACT_RP_LONG_RIGHT:
+ for (p = value; p <= end; ++p)
+ {
+ if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
+ {
+ char *newval;
+ newval = malloc (p - value + 1);
+
+ if (newval == NULL)
+ {
+ if (free_value)
+ free (value);
+ goto no_space;
+ }
+
+ *(char *) __mempcpy (newval, value, p - value) = '\0';
+ if (free_value)
+ free (value);
+ value = newval;
+ free_value = 1;
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ case ACT_NULL_ERROR:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ error = 0;
+ if (!colon_seen && value)
+ /* Substitute NULL */
+ ;
+ else
+ {
+ const char *str = pattern;
+
+ if (str[0] == '\0')
+ str = _("parameter null or not set");
+
+ __fxprintf (NULL, "%s: %s\n", env, str);
+ }
+
+ if (free_value)
+ free (value);
+ goto do_error;
+
+ case ACT_NULL_SUBST:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ if (free_value && value)
+ free (value);
+
+ if (!colon_seen && value)
+ /* Substitute NULL */
+ goto success;
+
+ value = pattern ? __strdup (pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ break;
+
+ case ACT_NONNULL_SUBST:
+ if (value && (*value || !colon_seen))
+ {
+ if (free_value && value)
+ free (value);
+
+ value = pattern ? __strdup (pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ break;
+ }
+
+ /* Substitute NULL */
+ if (free_value)
+ free (value);
+ goto success;
+
+ case ACT_NULL_ASSIGN:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ if (!colon_seen && value)
+ {
+ /* Substitute NULL */
+ if (free_value)
+ free (value);
+ goto success;
+ }
+
+ if (free_value)
+ free (value);
+
+ value = pattern ? __strdup (pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ __setenv (env, value, 1);
+ break;
+
+ default:
+ assert (! "Unrecognised action!");
+ }
+ }
+
+ free (env);
+ env = NULL;
+ free (pattern);
+ pattern = NULL;
+
+ if (seen_hash)
+ {
+ char param_length[21];
+ param_length[20] = '\0';
+ *word = w_addstr (*word, word_length, max_length,
+ _itoa_word (value ? strlen (value) : 0,
+ &param_length[20], 10, 0));
+ if (free_value)
+ {
+ assert (value != NULL);
+ free (value);
+ }
+
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ if (value == NULL)
+ return 0;
+
+ if (quoted || !pwordexp)
+ {
+ /* Quoted - no field split */
+ *word = w_addstr (*word, word_length, max_length, value);
+ if (free_value)
+ free (value);
+
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ else
+ {
+ /* Need to field-split */
+ char *value_copy = __strdup (value); /* Don't modify value */
+ char *field_begin = value_copy;
+ int seen_nonws_ifs = 0;
+
+ if (free_value)
+ free (value);
+
+ if (value_copy == NULL)
+ goto no_space;
+
+ do
+ {
+ char *field_end = field_begin;
+ char *next_field;
+
+ /* If this isn't the first field, start a new word */
+ if (field_begin != value_copy)
+ {
+ if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
+ {
+ free (value_copy);
+ goto no_space;
+ }
+
+ *word = w_newword (word_length, max_length);
+ }
+
+ /* Skip IFS whitespace before the field */
+ field_begin += strspn (field_begin, ifs_white);
+
+ if (!seen_nonws_ifs && *field_begin == 0)
+ /* Nothing but whitespace */
+ break;
+
+ /* Search for the end of the field */
+ field_end = field_begin + strcspn (field_begin, ifs);
+
+ /* Set up pointer to the character after end of field and
+ skip whitespace IFS after it. */
+ next_field = field_end + strspn (field_end, ifs_white);
+
+ /* Skip at most one non-whitespace IFS character after the field */
+ seen_nonws_ifs = 0;
+ if (*next_field && strchr (ifs, *next_field))
+ {
+ seen_nonws_ifs = 1;
+ next_field++;
+ }
+
+ /* Null-terminate it */
+ *field_end = 0;
+
+ /* Tag a copy onto the current word */
+ *word = w_addstr (*word, word_length, max_length, field_begin);
+
+ if (*word == NULL && *field_begin != '\0')
+ {
+ free (value_copy);
+ goto no_space;
+ }
+
+ field_begin = next_field;
+ }
+ while (seen_nonws_ifs || *field_begin);
+
+ free (value_copy);
+ }
+
+ return 0;
+
+success:
+ error = 0;
+ goto do_error;
+
+no_space:
+ error = WRDE_NOSPACE;
+ goto do_error;
+
+syntax:
+ error = WRDE_SYNTAX;
+
+do_error:
+ free (env);
+
+ free (pattern);
+
+ return error;
+}
+
+static int
+internal_function
+parse_dollars (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
+ int quoted)
+{
+ /* We are poised _at_ "$" */
+ switch (words[1 + *offset])
+ {
+ case '"':
+ case '\'':
+ case 0:
+ *word = w_addchar (*word, word_length, max_length, '$');
+ return *word ? 0 : WRDE_NOSPACE;
+
+ case '(':
+ if (words[2 + *offset] == '(')
+ {
+ /* Differentiate between $((1+3)) and $((echo);(ls)) */
+ int i = 3 + *offset;
+ int depth = 0;
+ while (words[i] && !(depth == 0 && words[i] == ')'))
+ {
+ if (words[i] == '(')
+ ++depth;
+ else if (words[i] == ')')
+ --depth;
+
+ ++i;
+ }
+
+ if (words[i] == ')' && words[i + 1] == ')')
+ {
+ (*offset) += 3;
+ /* Call parse_arith -- 0 is for "no brackets" */
+ return parse_arith (word, word_length, max_length, words, offset,
+ flags, 0);
+ }
+ }
+
+ if (flags & WRDE_NOCMD)
+ return WRDE_CMDSUB;
+
+ (*offset) += 2;
+ return parse_comm (word, word_length, max_length, words, offset, flags,
+ quoted? NULL : pwordexp, ifs, ifs_white);
+
+ case '[':
+ (*offset) += 2;
+ /* Call parse_arith -- 1 is for "brackets" */
+ return parse_arith (word, word_length, max_length, words, offset, flags,
+ 1);
+
+ case '{':
+ default:
+ ++(*offset); /* parse_param needs to know if "{" is there */
+ return parse_param (word, word_length, max_length, words, offset, flags,
+ pwordexp, ifs, ifs_white, quoted);
+ }
+}
+
+static int
+internal_function
+parse_backtick (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after "`" */
+ int error;
+ int squoting = 0;
+ size_t comm_length;
+ size_t comm_maxlen;
+ char *comm = w_newword (&comm_length, &comm_maxlen);
+
+ for (; words[*offset]; ++(*offset))
+ {
+ switch (words[*offset])
+ {
+ case '`':
+ /* Go -- give the script to the shell */
+ error = exec_comm (comm, word, word_length, max_length, flags,
+ pwordexp, ifs, ifs_white);
+ free (comm);
+ return error;
+
+ case '\\':
+ if (squoting)
+ {
+ error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
+ words, offset);
+
+ if (error)
+ {
+ free (comm);
+ return error;
+ }
+
+ break;
+ }
+
+ ++(*offset);
+ error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
+ offset);
+
+ if (error)
+ {
+ free (comm);
+ return error;
+ }
+
+ break;
+
+ case '\'':
+ squoting = 1 - squoting;
+ default:
+ comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
+ if (comm == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Premature end */
+ free (comm);
+ return WRDE_SYNTAX;
+}
+
+static int
+internal_function
+parse_dquote (char **word, size_t *word_length, size_t *max_length,
+ const char *words, size_t *offset, int flags,
+ wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
+{
+ /* We are poised just after a double-quote */
+ int error;
+
+ for (; words[*offset]; ++(*offset))
+ {
+ switch (words[*offset])
+ {
+ case '"':
+ return 0;
+
+ case '$':
+ error = parse_dollars (word, word_length, max_length, words, offset,
+ flags, pwordexp, ifs, ifs_white, 1);
+ /* The ``1'' here is to tell parse_dollars not to
+ * split the fields. It may need to, however ("$@").
+ */
+ if (error)
+ return error;
+
+ break;
+
+ case '`':
+ if (flags & WRDE_NOCMD)
+ return WRDE_CMDSUB;
+
+ ++(*offset);
+ error = parse_backtick (word, word_length, max_length, words,
+ offset, flags, NULL, NULL, NULL);
+ /* The first NULL here is to tell parse_backtick not to
+ * split the fields.
+ */
+ if (error)
+ return error;
+
+ break;
+
+ case '\\':
+ error = parse_qtd_backslash (word, word_length, max_length, words,
+ offset);
+
+ if (error)
+ return error;
+
+ break;
+
+ default:
+ *word = w_addchar (*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Unterminated string */
+ return WRDE_SYNTAX;
+}
+
+/*
+ * wordfree() is to be called after pwordexp is finished with.
+ */
+
+void
+wordfree (wordexp_t *pwordexp)
+{
+
+ /* wordexp can set pwordexp to NULL */
+ if (pwordexp && pwordexp->we_wordv)
+ {
+ char **wordv = pwordexp->we_wordv;
+
+ for (wordv += pwordexp->we_offs; *wordv; ++wordv)
+ free (*wordv);
+
+ free (pwordexp->we_wordv);
+ pwordexp->we_wordv = NULL;
+ }
+}
+libc_hidden_def (wordfree)
+
+/*
+ * wordexp()
+ */
+
+int
+wordexp (const char *words, wordexp_t *pwordexp, int flags)
+{
+ size_t words_offset;
+ size_t word_length;
+ size_t max_length;
+ char *word = w_newword (&word_length, &max_length);
+ int error;
+ char *ifs;
+ char ifs_white[4];
+ wordexp_t old_word = *pwordexp;
+
+ if (flags & WRDE_REUSE)
+ {
+ /* Minimal implementation of WRDE_REUSE for now */
+ wordfree (pwordexp);
+ old_word.we_wordv = NULL;
+ }
+
+ if ((flags & WRDE_APPEND) == 0)
+ {
+ pwordexp->we_wordc = 0;
+
+ if (flags & WRDE_DOOFFS)
+ {
+ pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
+ if (pwordexp->we_wordv == NULL)
+ {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+ }
+ else
+ {
+ pwordexp->we_wordv = calloc (1, sizeof (char *));
+ if (pwordexp->we_wordv == NULL)
+ {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+
+ pwordexp->we_offs = 0;
+ }
+ }
+
+ /* Find out what the field separators are.
+ * There are two types: whitespace and non-whitespace.
+ */
+ ifs = getenv ("IFS");
+
+ if (ifs == NULL)
+ /* IFS unset - use <space><tab><newline>. */
+ ifs = strcpy (ifs_white, " \t\n");
+ else
+ {
+ char *ifsch = ifs;
+ char *whch = ifs_white;
+
+ while (*ifsch != '\0')
+ {
+ if (*ifsch == ' ' || *ifsch == '\t' || *ifsch == '\n')
+ {
+ /* Whitespace IFS. See first whether it is already in our
+ collection. */
+ char *runp = ifs_white;
+
+ while (runp < whch && *runp != *ifsch)
+ ++runp;
+
+ if (runp == whch)
+ *whch++ = *ifsch;
+ }
+
+ ++ifsch;
+ }
+ *whch = '\0';
+ }
+
+ for (words_offset = 0 ; words[words_offset] ; ++words_offset)
+ switch (words[words_offset])
+ {
+ case '\\':
+ error = parse_backslash (&word, &word_length, &max_length, words,
+ &words_offset);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '$':
+ error = parse_dollars (&word, &word_length, &max_length, words,
+ &words_offset, flags, pwordexp, ifs, ifs_white,
+ 0);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '`':
+ if (flags & WRDE_NOCMD)
+ {
+ error = WRDE_CMDSUB;
+ goto do_error;
+ }
+
+ ++words_offset;
+ error = parse_backtick (&word, &word_length, &max_length, words,
+ &words_offset, flags, pwordexp, ifs,
+ ifs_white);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '"':
+ ++words_offset;
+ error = parse_dquote (&word, &word_length, &max_length, words,
+ &words_offset, flags, pwordexp, ifs, ifs_white);
+
+ if (error)
+ goto do_error;
+
+ if (!word_length)
+ {
+ error = w_addword (pwordexp, NULL);
+
+ if (error)
+ return error;
+ }
+
+ break;
+
+ case '\'':
+ ++words_offset;
+ error = parse_squote (&word, &word_length, &max_length, words,
+ &words_offset);
+
+ if (error)
+ goto do_error;
+
+ if (!word_length)
+ {
+ error = w_addword (pwordexp, NULL);
+
+ if (error)
+ return error;
+ }
+
+ break;
+
+ case '~':
+ error = parse_tilde (&word, &word_length, &max_length, words,
+ &words_offset, pwordexp->we_wordc);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '*':
+ case '[':
+ case '?':
+ error = parse_glob (&word, &word_length, &max_length, words,
+ &words_offset, flags, pwordexp, ifs, ifs_white);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ default:
+ /* Is it a word separator? */
+ if (strchr (" \t", words[words_offset]) == NULL)
+ {
+ char ch = words[words_offset];
+
+ /* Not a word separator -- but is it a valid word char? */
+ if (strchr ("\n|&;<>(){}", ch))
+ {
+ /* Fail */
+ error = WRDE_BADCHAR;
+ goto do_error;
+ }
+
+ /* "Ordinary" character -- add it to word */
+ word = w_addchar (word, &word_length, &max_length,
+ ch);
+ if (word == NULL)
+ {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+
+ break;
+ }
+
+ /* If a word has been delimited, add it to the list. */
+ if (word != NULL)
+ {
+ error = w_addword (pwordexp, word);
+ if (error)
+ goto do_error;
+ }
+
+ word = w_newword (&word_length, &max_length);
+ }
+
+ /* End of string */
+
+ /* There was a word separator at the end */
+ if (word == NULL) /* i.e. w_newword */
+ return 0;
+
+ /* There was no field separator at the end */
+ return w_addword (pwordexp, word);
+
+do_error:
+ /* Error:
+ * free memory used (unless error is WRDE_NOSPACE), and
+ * set pwordexp members back to what they were.
+ */
+
+ free (word);
+
+ if (error == WRDE_NOSPACE)
+ return WRDE_NOSPACE;
+
+ if ((flags & WRDE_APPEND) == 0)
+ wordfree (pwordexp);
+
+ *pwordexp = old_word;
+ return error;
+}
diff --git a/libc/posix/wordexp.h b/libc/posix/wordexp.h
new file mode 100644
index 000000000..1c40e6168
--- /dev/null
+++ b/libc/posix/wordexp.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 1991, 92, 1996-1999, 2001, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _WORDEXP_H
+#define _WORDEXP_H 1
+
+#include <features.h>
+#define __need_size_t
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+/* Bits set in the FLAGS argument to `wordexp'. */
+enum
+ {
+ WRDE_DOOFFS = (1 << 0), /* Insert PWORDEXP->we_offs NULLs. */
+ WRDE_APPEND = (1 << 1), /* Append to results of a previous call. */
+ WRDE_NOCMD = (1 << 2), /* Don't do command substitution. */
+ WRDE_REUSE = (1 << 3), /* Reuse storage in PWORDEXP. */
+ WRDE_SHOWERR = (1 << 4), /* Don't redirect stderr to /dev/null. */
+ WRDE_UNDEF = (1 << 5), /* Error for expanding undefined variables. */
+ __WRDE_FLAGS = (WRDE_DOOFFS | WRDE_APPEND | WRDE_NOCMD |
+ WRDE_REUSE | WRDE_SHOWERR | WRDE_UNDEF)
+ };
+
+/* Structure describing a word-expansion run. */
+typedef struct
+ {
+ size_t we_wordc; /* Count of words matched. */
+ char **we_wordv; /* List of expanded words. */
+ size_t we_offs; /* Slots to reserve in `we_wordv'. */
+ } wordexp_t;
+
+/* Possible nonzero return values from `wordexp'. */
+enum
+ {
+#ifdef __USE_XOPEN
+ WRDE_NOSYS = -1, /* Never used since we support `wordexp'. */
+#endif
+ WRDE_NOSPACE = 1, /* Ran out of memory. */
+ WRDE_BADCHAR, /* A metachar appears in the wrong place. */
+ WRDE_BADVAL, /* Undefined var reference with WRDE_UNDEF. */
+ WRDE_CMDSUB, /* Command substitution with WRDE_NOCMD. */
+ WRDE_SYNTAX /* Shell syntax error. */
+ };
+
+/* Do word expansion of WORDS into PWORDEXP. */
+extern int wordexp (__const char *__restrict __words,
+ wordexp_t *__restrict __pwordexp, int __flags);
+
+/* Free the storage allocated by a `wordexp' call. */
+extern void wordfree (wordexp_t *__wordexp) __THROW;
+
+__END_DECLS
+
+#endif /* wordexp.h */