diff options
author | gcc <gcc@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2006-08-17 01:18:26 +0000 |
---|---|---|
committer | gcc <gcc@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2006-08-17 01:18:26 +0000 |
commit | 15f34685e7a9b5caf761af2ebf6afa20438d440b (patch) | |
tree | dc04ce3cdf040f198743c15b64557824de174680 /libc/posix | |
parent | 1e848e0e775a36f6359161f5deb890942ef42ff3 (diff) | |
download | eglibc2-15f34685e7a9b5caf761af2ebf6afa20438d440b.tar.gz |
Import glibc-mainline for 2006-08-16
git-svn-id: svn://svn.eglibc.org/fsf/trunk@4 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/posix')
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 (®ex, '\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, ®ex); + if (s != NULL) + { + puts ("re_compile_pattern return non-NULL value"); + result = 1; + } + else + { + match = re_match (®ex, "an", 2, 0, ®s); + 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, ®ex); + if (s != NULL) + { + puts ("re_compile_pattern return non-NULL value"); + result = 1; + } + else + { + match = re_match (®ex, "an", 2, 0, ®s); + 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 (®ex, '\0', sizeof (regex)); + s = re_compile_pattern ("[abc]*d", 7, ®ex); + if (s != NULL) + { + puts ("re_compile_pattern return non-NULL value"); + result = 1; + } + else + { + match = re_match (®ex, "foacabdxy", 9, 2, ®s); + 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 (®buf, '\0', sizeof (regbuf)); + err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern), + ®buf); + if (err != NULL) + { + printf ("re_compile_pattern failed: %s\n", err); + ret = 1; + continue; + } + + start = re_search (®buf, 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 (®buf); + continue; + } + regfree (®buf); + } + + 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 (®buf, '\0', sizeof (regbuf)); + err = re_compile_pattern (test->pattern, strlen (test->pattern), + ®buf); + if (err != NULL) + { + printf ("%sre_compile_pattern \"%s\" failed: %s\n", fail, test->pattern, + err); + return 1; + } + + res = re_search (®buf, 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 (®buf); + return 1; + } + + if (test->res > 0 && test->start == 0) + { + res = re_search (®buf, 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 (®buf); + return 1; + } + } + + regfree (®buf); + 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 (®buf, '\0', sizeof (regbuf)); + err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern), + ®buf); + 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 (®buf, 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 (®buf); + continue; + } + + res = re_search (®buf, 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 (®buf); + continue; + } + regfree (®buf); + + re_set_syntax (tests[i].syntax | RE_ICASE); + memset (®buf, '\0', sizeof (regbuf)); + err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern), + ®buf); + 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 (®buf, 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 (®buf); + continue; + } + + res = re_search (®buf, 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 (®buf); + continue; + } + regfree (®buf); + } + + 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 (®s, 0, sizeof (regs)); + + re_compile_pattern ("$", 1, &re); + + int ret = 0, r = re_search (&re, str1, 4, 0, 4, ®s); + if (r != 4) + { + printf ("First re_search returned %d\n", r); + ret = 1; + } + r = re_search (&re, str2, 4, 0, 4, ®s); + 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 (®ex, '\0', sizeof (regex)); + + setlocale (LC_ALL, "C"); + + s = re_compile_pattern ("ab[cde]", 7, ®ex); + if (s != NULL) + { + puts ("re_compile_pattern returned non-NULL value"); + result = 1; + } + else + { + match[0] = re_search_2 (®ex, "xyabez", 6, "", 0, 1, 5, NULL, 6); + match[1] = re_search_2 (®ex, NULL, 0, "abc", 3, 0, 3, NULL, 3); + match[2] = re_search_2 (®ex, "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 (®ex, '\0', sizeof (regex)); + regs.start = regs.end = NULL; + regs.num_regs = 0; + s = re_compile_pattern ("a", 1, ®ex); + if (s != NULL) + { + puts ("failed to compile pattern \"a\""); + result = 1; + } + else + { + match = re_search (®ex, "baobab", 6, 0, 6, ®s); + 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 (®ex, '\0', sizeof (regex)); + + s = re_compile_pattern ("\\(\\(\\(a\\)\\)\\)", 13, ®ex); + if (s != NULL) + { + puts ("failed to compile pattern /\\(\\(\\(a\\)\\)\\)/"); + result = 1; + } + else + { + match = re_match (®ex, "apl", 3, 0, ®s); + 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 (®ex, '\0', sizeof (regex)); + + s = re_compile_pattern ("xy$", 3, ®ex); + if (s != NULL) + { + puts ("failed to compile pattern \"xy$\""); + return 1; + } + else + match[0] = re_match_2(®ex,"xyz",3,NULL,0,0,NULL,2); + + free (regex.buffer); + memset (®ex, '\0', sizeof (regex)); + + s = re_compile_pattern ("xy\\>", 4, ®ex); + if (s != NULL) + { + puts ("failed to compile pattern \"xy\\>\""); + return 1; + } + else + match[1] = re_search_2(®ex,"xyz",3,NULL,0,0,2,NULL,2); + + free (regex.buffer); + memset (®ex, '\0', sizeof (regex)); + + s = re_compile_pattern ("xy \\<", 5, ®ex); + if (s != NULL) + { + puts ("failed to compile pattern \"xy \\<\""); + return 1; + } + else + { + match[2] = re_match_2(®ex,"xy ",4,NULL,0,0,NULL,3); + match[3] = re_match_2(®ex,"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 (®exp, 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 (®exp); + 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 (®exp, 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 (®exp); + + 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 (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); + tree = parse_reg_exp (regexp, preg, ¤t_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), ®s[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), ®s[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, ®s[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 (®s, 0, sizeof (regs)); + int match = re_search (&rpbuf, string, len, 0, len, + ®s); + 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, "&ersand", 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, + ¶m_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 */ |