diff options
author | Zack Weinberg <zackw@panix.com> | 2017-06-08 15:39:03 -0400 |
---|---|---|
committer | Zack Weinberg <zackw@panix.com> | 2017-06-08 15:39:03 -0400 |
commit | 5046dbb4a7eba5eccfd258f92f4735c9ffc8d069 (patch) | |
tree | 4470480d904b65cf14ca524f96f79eca818c3eaf /REORG.TODO/posix | |
parent | 199fc19d3aaaf57944ef036e15904febe877fc93 (diff) | |
download | glibc-zack/build-layout-experiment.tar.gz glibc-zack/build-layout-experiment.tar.xz glibc-zack/build-layout-experiment.zip |
Prepare for radical source tree reorganization. zack/build-layout-experiment
All top-level files and directories are moved into a temporary storage directory, REORG.TODO, except for files that will certainly still exist in their current form at top level when we're done (COPYING, COPYING.LIB, LICENSES, NEWS, README), all old ChangeLog files (which are moved to the new directory OldChangeLogs, instead), and the generated file INSTALL (which is just deleted; in the new order, there will be no generated files checked into version control).
Diffstat (limited to 'REORG.TODO/posix')
286 files changed, 50461 insertions, 0 deletions
diff --git a/REORG.TODO/posix/BOOST.tests b/REORG.TODO/posix/BOOST.tests new file mode 100644 index 0000000000..98fd3b6abf --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/Depend b/REORG.TODO/posix/Depend new file mode 100644 index 0000000000..f3e1156a4e --- /dev/null +++ b/REORG.TODO/posix/Depend @@ -0,0 +1 @@ +localedata diff --git a/REORG.TODO/posix/Makefile b/REORG.TODO/posix/Makefile new file mode 100644 index 0000000000..52b022cf66 --- /dev/null +++ b/REORG.TODO/posix/Makefile @@ -0,0 +1,375 @@ +# Copyright (C) 1991-2017 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, see +# <http://www.gnu.org/licenses/>. + +# +# Sub-makefile for POSIX portion of the library. +# +subdir := posix + +include ../Makeconfig + +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/getopt_core.h bits/getopt_ext.h bits/getopt_posix.h \ + bits/types.h bits/typesizes.h bits/pthreadtypes.h \ + bits/pthreadtypes-arch.h bits/thread-shared-types.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 \ + spawn.h bits/unistd.h + +routines := \ + uname \ + times \ + wait waitpid wait3 wait4 waitid \ + alarm sleep pause nanosleep \ + fork vfork _exit \ + execve fexecve execv execle execl execvp execlp execvpe \ + getpid getppid \ + getuid geteuid getgid getegid getgroups setuid setgid group_member \ + getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \ + getresuid getresgid setresuid setresgid \ + pathconf sysconf fpathconf \ + glob glob64 fnmatch regex \ + confstr \ + getopt getopt1 \ + 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 spawn_valid_fd \ + 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 sched_cpucount sched_cpualloc sched_cpufree + +aux := init-posix environ +tests := test-errno tstgetopt testfnm runtests runptests \ + tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \ + tst-mmap tst-mmap-offset 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-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-regex21 bug-regex22 bug-regex23 bug-regex24 \ + bug-regex25 bug-regex26 bug-regex27 bug-regex28 \ + bug-regex29 bug-regex30 bug-regex31 bug-regex32 \ + tst-nice tst-nanosleep tst-regex2 \ + transbug tst-rxspencer tst-pcre tst-boost \ + bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \ + tst-getaddrinfo2 bug-glob1 bug-glob2 bug-glob3 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-execvpe1 tst-execvpe2 tst-execvpe3 tst-execvpe4 \ + tst-execvpe5 tst-execvpe6 \ + tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \ + bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \ + bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \ + tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ + tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ + tst-posix_spawn-fd tst-posix_spawn-setsid \ + tst-posix_fadvise tst-posix_fadvise64 +tests-internal := bug-regex5 bug-regex20 bug-regex33 \ + tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 +xtests := bug-ga2 +ifeq (yes,$(build-shared)) +test-srcs := globtest +tests += wordexp-test tst-exec tst-spawn tst-spawn2 tst-spawn3 +endif +ifeq (yesyes,$(build-shared)$(have-thread-library)) +tests += tst-getopt-cancel +endif +tests-static = tst-exec-static tst-spawn-static +tests += $(tests-static) +others := getconf +install-bin := getconf +install-others-programs := $(inst_libexecdir)/getconf + +before-compile += testcases.h ptestcases.h $(objpfx)posix-conf-vars-def.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.out \ + bug-regex2.mtrace bug-regex14-mem.out bug-regex14.mtrace \ + bug-regex21-mem.out bug-regex21.mtrace \ + bug-regex31-mem.out bug-regex31.mtrace \ + tst-rxspencer-no-utf8-mem.out tst-rxspencer-no-utf8.mtrace \ + tst-getconf.out \ + tst-pcre-mem.out tst-pcre.mtrace tst-boost-mem.out \ + tst-boost.mtrace bug-ga2.mtrace bug-ga2-mem.out \ + bug-glob2.mtrace bug-glob2-mem.out tst-vfork3-mem.out \ + tst-vfork3.mtrace getconf.speclist tst-fnmatch-mem.out \ + tst-fnmatch.mtrace bug-regex36.mtrace + +ifeq ($(run-built-tests),yes) +ifeq (yes,$(build-shared)) +tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out +endif +endif + +# Run a test on the header files we use. +# XXX Please note that for now we ignore the result of this test. +tests-special += $(objpfx)annexc.out +ifeq ($(run-built-tests),yes) +tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \ + $(objpfx)bug-regex21-mem.out $(objpfx)bug-regex31-mem.out \ + $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \ + $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \ + $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \ + $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out +xtests-special += $(objpfx)bug-ga2-mem.out +endif + +include ../Rules + +ifeq ($(run-built-tests),yes) +# globtest and wordexp-test currently only works with shared libraries +ifeq (yes,$(build-shared)) +$(objpfx)globtest.out: globtest.sh $(objpfx)globtest + $(SHELL) $< $(common-objpfx) '$(test-via-rtld-prefix)' \ + '$(test-program-prefix)' '$(test-wrapper-env)'; \ + $(evaluate-test) +$(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test + $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \ + '$(run-program-env)' '$(test-program-prefix-after-env)'; \ + $(evaluate-test) +endif + +LOCALES := cs_CZ.UTF-8 da_DK.ISO-8859-1 de_DE.ISO-8859-1 de_DE.UTF-8 \ + en_US.UTF-8 es_US.ISO-8859-1 es_US.UTF-8 ja_JP.EUC-JP tr_TR.UTF-8 +include ../gen-locales.mk + +$(objpfx)bug-regex1.out: $(gen-locales) +$(objpfx)bug-regex4.out: $(gen-locales) +$(objpfx)bug-regex5.out: $(gen-locales) +$(objpfx)bug-regex6.out: $(gen-locales) +$(objpfx)bug-regex17.out: $(gen-locales) +$(objpfx)bug-regex18.out: $(gen-locales) +$(objpfx)bug-regex19.out: $(gen-locales) +$(objpfx)bug-regex20.out: $(gen-locales) +$(objpfx)bug-regex22.out: $(gen-locales) +$(objpfx)bug-regex23.out: $(gen-locales) +$(objpfx)bug-regex25.out: $(gen-locales) +$(objpfx)bug-regex26.out: $(gen-locales) +$(objpfx)bug-regex30.out: $(gen-locales) +$(objpfx)bug-regex32.out: $(gen-locales) +$(objpfx)bug-regex33.out: $(gen-locales) +$(objpfx)bug-regex34.out: $(gen-locales) +$(objpfx)bug-regex35.out: $(gen-locales) +$(objpfx)tst-fnmatch.out: $(gen-locales) +$(objpfx)tst-fnmatch4.out: $(gen-locales) +$(objpfx)tst-fnmatch5.out: $(gen-locales) +$(objpfx)tst-regex.out: $(gen-locales) +$(objpfx)tst-regex2.out: $(gen-locales) +$(objpfx)tst-regexloc.out: $(gen-locales) +$(objpfx)tst-rxspencer.out: $(gen-locales) +$(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales) +endif + +# If we will use the generic uname implementation, we must figure out what +# it will say by examining the system, and write the results in config-name.h. +uname.c: $(objpfx)config-name.h +$(objpfx)config-name.h: $(..)scripts/config-uname.sh $(common-objpfx)config.make + $(make-target-directory) + $< '$(config-os)' '$(config-release)' \ + '$(config-machine)-$(config-vendor)' > $@.new + mv -f $@.new $@ + +CFLAGS-getaddrinfo.c = -DRESOLVER -fexceptions +CFLAGS-pause.c = -fexceptions -fasynchronous-unwind-tables +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-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 +CFLAGS-nanosleep.c = -fexceptions -fasynchronous-unwind-tables + +tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \ + --none random --col --color --colour + +tst-exec-ARGS = -- $(host-test-program-cmd) +tst-exec-static-ARGS = $(tst-exec-ARGS) +tst-execvpe5-ARGS = -- $(host-test-program-cmd) +tst-spawn-ARGS = -- $(host-test-program-cmd) +tst-spawn-static-ARGS = $(tst-spawn-ARGS) +tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir +tst-chmod-ARGS = $(objdir) +tst-vfork3-ARGS = --test-dir=$(objpfx) + +tst-rxspencer-ARGS = --utf8 rxspencer/tests +tst-rxspencer-no-utf8-ARGS = rxspencer/tests +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 + LC_ALL=C sed -f TESTS2C.sed < $< > $@T + mv -f $@T $@ + +ptestcases.h: PTESTS PTESTS2C.sed + LC_ALL=C sed -f PTESTS2C.sed < $< > $@T + mv -f $@T $@ + +$(objpfx)tst-getopt-cancel: $(shared-thread-library) + +test-xfail-annexc = yes +$(objpfx)annexc.out: $(objpfx)annexc + $(dir $<)$(notdir $<) '$(CC)' \ + '$(patsubst %,-I../%,$(sorted-subdirs)) -I../include $(+sysdep-includes) $(sysincludes) -I..' > $@; \ + $(evaluate-test) + +annexc-CFLAGS = -O +$(objpfx)annexc: annexc.c + $(native-compile) + +tst-fnmatch-ENV += MALLOC_TRACE=$(objpfx)tst-fnmatch.mtrace + +$(objpfx)tst-fnmatch-mem.out: $(objpfx)tst-fnmatch.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-fnmatch.mtrace > $@; \ + $(evaluate-test) + +bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace + +$(objpfx)bug-regex2-mem.out: $(objpfx)bug-regex2.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-regex2.mtrace > $@; \ + $(evaluate-test) + +bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace + +$(objpfx)bug-regex14-mem.out: $(objpfx)bug-regex14.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-regex14.mtrace > $@; \ + $(evaluate-test) + +bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace + +$(objpfx)bug-regex21-mem.out: $(objpfx)bug-regex21.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@; \ + $(evaluate-test) + +bug-regex31-ENV = MALLOC_TRACE=$(objpfx)bug-regex31.mtrace + +$(objpfx)bug-regex31-mem.out: $(objpfx)bug-regex31.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-regex31.mtrace > $@; \ + $(evaluate-test) + +bug-regex36-ENV = MALLOC_TRACE=$(objpfx)bug-regex36.mtrace + +$(objpfx)bug-regex36-mem.out: $(objpfx)bug-regex36.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-regex36.mtrace > $@; \ + $(evaluate-test) + +tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace + +$(objpfx)tst-vfork3-mem.out: $(objpfx)tst-vfork3.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-vfork3.mtrace > $@; \ + $(evaluate-test) + +# tst-rxspencer.mtrace is not generated, only +# tst-rxspencer-no-utf8.mtrace, since otherwise the file has almost +# 100M and takes very long time to process. +tst-rxspencer-no-utf8-ENV += MALLOC_TRACE=$(objpfx)tst-rxspencer-no-utf8.mtrace +$(objpfx)tst-rxspencer-no-utf8-mem.out: $(objpfx)tst-rxspencer-no-utf8.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-rxspencer-no-utf8.mtrace \ + > $@; \ + $(evaluate-test) + +tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace +$(objpfx)tst-pcre-mem.out: $(objpfx)tst-pcre.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-pcre.mtrace > $@; \ + $(evaluate-test) + +tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace +$(objpfx)tst-boost-mem.out: $(objpfx)tst-boost.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-boost.mtrace > $@; \ + $(evaluate-test) + +$(objpfx)tst-getconf.out: tst-getconf.sh $(objpfx)getconf + $(SHELL) $< $(common-objpfx) '$(built-program-cmd)'; \ + $(evaluate-test) + +$(objpfx)bug-ga2-mem.out: $(objpfx)bug-ga2.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-ga2.mtrace > $@; \ + $(evaluate-test) + +bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace + +bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace + +$(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \ + $(evaluate-test) + +$(inst_libexecdir)/getconf: $(inst_bindir)/getconf \ + $(objpfx)getconf.speclist FORCE + $(addprefix $(..)./scripts/mkinstalldirs ,\ + $(filter-out $(wildcard $@),$@)) + while read spec; do \ + ln -f $< $@/$$spec.new || $(INSTALL_PROGRAM) $< $@/$$spec.new; \ + mv -f $@/$$spec.new $@/$$spec; \ + done < $(objpfx)getconf.speclist + +$(objpfx)getconf.speclist: getconf-speclist.c posix-envs.def + $(compile.c) -E -o - \ + | sed -n -e '/@@@PRESENT_/s/@@@PRESENT_//p' > $@.new + mv -f $@.new $@ + +# This file is only actually needed at install time. But forcing it to +# be built both makes it available for eyeball inspection and avoids the +# surprise of things that look like compilation being done by 'make install'. +others: $(objpfx)getconf.speclist + +$(objpfx)posix-conf-vars-def.h: $(..)scripts/gen-posix-conf-vars.awk \ + posix-conf-vars.list Makefile + $(make-target-directory) + $(AWK) -f $(filter-out Makefile, $^) > $@.tmp + mv -f $@.tmp $@ diff --git a/REORG.TODO/posix/PCRE.tests b/REORG.TODO/posix/PCRE.tests new file mode 100644 index 0000000000..0fb9cadafc --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/PTESTS b/REORG.TODO/posix/PTESTS new file mode 100644 index 0000000000..02b357cf2e --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/PTESTS2C.sed b/REORG.TODO/posix/PTESTS2C.sed new file mode 100644 index 0000000000..b6850a3754 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/TESTS b/REORG.TODO/posix/TESTS new file mode 100644 index 0000000000..f2c9886405 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/TESTS2C.sed b/REORG.TODO/posix/TESTS2C.sed new file mode 100644 index 0000000000..d8c2d72617 --- /dev/null +++ b/REORG.TODO/posix/TESTS2C.sed @@ -0,0 +1,2 @@ +s/\\/\\\\/g +s/\([0-9]*\):\(.*\):\(.*\)/ {\1, "\2", "\3"},/ diff --git a/REORG.TODO/posix/Versions b/REORG.TODO/posix/Versions new file mode 100644 index 0000000000..bb481a505b --- /dev/null +++ b/REORG.TODO/posix/Versions @@ -0,0 +1,140 @@ +libc { + GLIBC_2.0 { + # functions with special/multiple interfaces + __bsd_getpgrp; __getpgid; __setpgid; + + # 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; + 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. + getresgid; getresuid; setresgid; setresuid; + } + GLIBC_2.3.3 { + sched_getaffinity; sched_setaffinity; + } + GLIBC_2.3.4 { + regexec; + } + GLIBC_2.6 { + __sched_cpucount; + } + GLIBC_2.7 { + __sched_cpualloc; __sched_cpufree; + } + GLIBC_2.10 { + __posix_getopt; + } + GLIBC_2.11 { + execvpe; + } + GLIBC_PRIVATE { + __libc_fork; __libc_pread; __libc_pwrite; + } +} diff --git a/REORG.TODO/posix/_exit.c b/REORG.TODO/posix/_exit.c new file mode 100644 index 0000000000..6f3f865e90 --- /dev/null +++ b/REORG.TODO/posix/_exit.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (int status) +{ + status &= 0xff; + abort (); +} +libc_hidden_def (_exit) +rtld_hidden_def (_exit) +weak_alias (_exit, _Exit) + +stub_warning (_exit) diff --git a/REORG.TODO/posix/alarm.c b/REORG.TODO/posix/alarm.c new file mode 100644 index 0000000000..f925f5112b --- /dev/null +++ b/REORG.TODO/posix/alarm.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (unsigned int seconds) +{ + __set_errno (ENOSYS); + return 0; +} +libc_hidden_def (alarm) + +stub_warning (alarm) diff --git a/REORG.TODO/posix/annexc.c b/REORG.TODO/posix/annexc.c new file mode 100644 index 0000000000..6fe9e04359 --- /dev/null +++ b/REORG.TODO/posix/annexc.c @@ -0,0 +1,889 @@ +/* Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bits/getopt_core.h b/REORG.TODO/posix/bits/getopt_core.h new file mode 100644 index 0000000000..1744c29b74 --- /dev/null +++ b/REORG.TODO/posix/bits/getopt_core.h @@ -0,0 +1,96 @@ +/* Declarations for getopt (basic, portable features only). + Copyright (C) 1989-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GETOPT_CORE_H +#define _GETOPT_CORE_H 1 + +/* This header should not be used directly; include getopt.h or + unistd.h instead. Unlike most bits headers, it does not have + a protective #error, because the guard macro for getopt.h in + gnulib is not fixed. */ + +__BEGIN_DECLS + +/* 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; + +/* 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 '\1'. This behavior is specific to the GNU + 'getopt'. If OPTS begins with '+', or POSIXLY_CORRECT is set in + the environment, then do not permute arguments. + + For standards compliance, the 'argv' argument has the type + char *const *, but this is inaccurate; if argument permutation is + enabled, the argv array (not the strings it points to) must be + writable. */ + +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW __nonnull ((2, 3)); + +__END_DECLS + +#endif /* getopt_core.h */ diff --git a/REORG.TODO/posix/bits/getopt_ext.h b/REORG.TODO/posix/bits/getopt_ext.h new file mode 100644 index 0000000000..c1a58da804 --- /dev/null +++ b/REORG.TODO/posix/bits/getopt_ext.h @@ -0,0 +1,77 @@ +/* Declarations for getopt (GNU extensions). + Copyright (C) 1989-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GETOPT_EXT_H +#define _GETOPT_EXT_H 1 + +/* This header should not be used directly; include getopt.h instead. + Unlike most bits headers, it does not have a protective #error, + because the guard macro for getopt.h in gnulib is not fixed. */ + +__BEGIN_DECLS + +/* 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 + +extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW __nonnull ((2, 3)); +extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW __nonnull ((2, 3)); + +__END_DECLS + +#endif /* getopt_ext.h */ diff --git a/REORG.TODO/posix/bits/getopt_posix.h b/REORG.TODO/posix/bits/getopt_posix.h new file mode 100644 index 0000000000..f9f3265a20 --- /dev/null +++ b/REORG.TODO/posix/bits/getopt_posix.h @@ -0,0 +1,51 @@ +/* Declarations for getopt (POSIX compatibility shim). + Copyright (C) 1989-2017 Free Software Foundation, Inc. + Unlike the bulk of the getopt implementation, this file is NOT part + of gnulib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GETOPT_POSIX_H +#define _GETOPT_POSIX_H 1 + +#if !defined _UNISTD_H && !defined _STDIO_H +#error "Never include getopt_posix.h directly; use unistd.h instead." +#endif + +#include <bits/getopt_core.h> + +__BEGIN_DECLS + +#if defined __USE_POSIX2 && !defined __USE_POSIX_IMPLICITLY \ + && !defined __USE_GNU && !defined _GETOPT_H +/* GNU getopt has more functionality than POSIX getopt. When we are + explicitly conforming to POSIX and not GNU, and getopt.h (which is + not part of POSIX) has not been included, the extra functionality + is disabled. */ +# ifdef __REDIRECT +extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, + const char *__shortopts), + __posix_getopt); +# else +extern int __posix_getopt (int ___argc, char *const *___argv, + const char *__shortopts) + __THROW __nonnull ((2, 3)); +# define getopt __posix_getopt +# endif +#endif + +__END_DECLS + +#endif /* getopt_posix.h */ diff --git a/REORG.TODO/posix/bits/posix1_lim.h b/REORG.TODO/posix/bits/posix1_lim.h new file mode 100644 index 0000000000..28f8a6c404 --- /dev/null +++ b/REORG.TODO/posix/bits/posix1_lim.h @@ -0,0 +1,175 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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 + +#if !defined __USE_XOPEN2K || defined __USE_GNU +/* Number of descriptors that a process may examine with `pselect' or + `select'. */ +# define _POSIX_FD_SETSIZE _POSIX_OPEN_MAX +#endif + +/* 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'). */ +#ifdef __USE_XOPEN2K +# define _POSIX_TZNAME_MAX 6 +#else +# define _POSIX_TZNAME_MAX 3 +#endif + +#if !defined __USE_XOPEN2K || defined __USE_GNU +/* 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 +#endif + +/* 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/REORG.TODO/posix/bits/posix2_lim.h b/REORG.TODO/posix/bits/posix2_lim.h new file mode 100644 index 0000000000..78ab6becbe --- /dev/null +++ b/REORG.TODO/posix/bits/posix2_lim.h @@ -0,0 +1,90 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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/REORG.TODO/posix/bits/types.h b/REORG.TODO/posix/bits/types.h new file mode 100644 index 0000000000..e2f73a89e4 --- /dev/null +++ b/REORG.TODO/posix/bits/types.h @@ -0,0 +1,207 @@ +/* bits/types.h -- definitions of __*_t types underlying *_t types. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * Never include this file directly; use <sys/types.h> instead. + */ + +#ifndef _BITS_TYPES_H +#define _BITS_TYPES_H 1 + +#include <features.h> +#include <bits/wordsize.h> + +/* Convenience types. */ +typedef unsigned char __u_char; +typedef unsigned short int __u_short; +typedef unsigned int __u_int; +typedef unsigned long int __u_long; + +/* Fixed-size types, underlying types depend on word size and compiler. */ +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; +#if __WORDSIZE == 64 +typedef signed long int __int64_t; +typedef unsigned long int __uint64_t; +#else +__extension__ typedef signed long long int __int64_t; +__extension__ typedef unsigned long long int __uint64_t; +#endif + +/* quad_t is also 64 bits. */ +#if __WORDSIZE == 64 +typedef long int __quad_t; +typedef unsigned long int __u_quad_t; +#else +__extension__ typedef long long int __quad_t; +__extension__ typedef unsigned long long int __u_quad_t; +#endif + +/* Largest integral types. */ +#if __WORDSIZE == 64 +typedef long int __intmax_t; +typedef unsigned long int __uintmax_t; +#else +__extension__ typedef long long int __intmax_t; +__extension__ typedef unsigned long long int __uintmax_t; +#endif + + +/* The machine-dependent file <bits/typesizes.h> defines __*_T_TYPE + macros for each of the OS types we define below. The definitions + of those macros must use the following macros for underlying types. + We define __S<SIZE>_TYPE and __U<SIZE>_TYPE for the signed and unsigned + variants of each of the following integer types on this machine. + + 16 -- "natural" 16-bit type (always short) + 32 -- "natural" 32-bit type (always int) + 64 -- "natural" 64-bit type (long or long long) + LONG32 -- 32-bit type, traditionally long + QUAD -- 64-bit type, always long long + WORD -- natural type of __WORDSIZE bits (int or long) + LONGWORD -- type of __WORDSIZE bits, traditionally long + + We distinguish WORD/LONGWORD, 32/LONG32, and 64/QUAD so that the + conventional uses of `long' or `long long' type modifiers match the + types we define, even when a less-adorned type would be the same size. + This matters for (somewhat) portably writing printf/scanf formats for + these types, where using the appropriate l or ll format modifiers can + make the typedefs and the formats match up across all GNU platforms. If + we used `long' when it's 64 bits where `long long' is expected, then the + compiler would warn about the formats not matching the argument types, + and the programmer changing them to shut up the compiler would break the + program's portability. + + Here we assume what is presently the case in all the GCC configurations + we support: long long is always 64 bits, long is always word/address size, + and int is always 32 bits. */ + +#define __S16_TYPE short int +#define __U16_TYPE unsigned short int +#define __S32_TYPE int +#define __U32_TYPE unsigned int +#define __SLONGWORD_TYPE long int +#define __ULONGWORD_TYPE unsigned long int +#if __WORDSIZE == 32 +# define __SQUAD_TYPE __quad_t +# define __UQUAD_TYPE __u_quad_t +# define __SWORD_TYPE int +# define __UWORD_TYPE unsigned int +# define __SLONG32_TYPE long int +# define __ULONG32_TYPE unsigned long int +# define __S64_TYPE __quad_t +# define __U64_TYPE __u_quad_t +/* We want __extension__ before typedef's that use nonstandard base types + such as `long long' in C89 mode. */ +# define __STD_TYPE __extension__ typedef +#elif __WORDSIZE == 64 +# define __SQUAD_TYPE long int +# define __UQUAD_TYPE unsigned long int +# define __SWORD_TYPE long int +# define __UWORD_TYPE unsigned long int +# define __SLONG32_TYPE int +# define __ULONG32_TYPE unsigned int +# define __S64_TYPE long int +# define __U64_TYPE unsigned long int +/* No need to mark the typedef with __extension__. */ +# define __STD_TYPE typedef +#else +# error +#endif +#include <bits/typesizes.h> /* Defines __*_T_TYPE macros. */ + + +__STD_TYPE __DEV_T_TYPE __dev_t; /* Type of device numbers. */ +__STD_TYPE __UID_T_TYPE __uid_t; /* Type of user identifications. */ +__STD_TYPE __GID_T_TYPE __gid_t; /* Type of group identifications. */ +__STD_TYPE __INO_T_TYPE __ino_t; /* Type of file serial numbers. */ +__STD_TYPE __INO64_T_TYPE __ino64_t; /* Type of file serial numbers (LFS).*/ +__STD_TYPE __MODE_T_TYPE __mode_t; /* Type of file attribute bitmasks. */ +__STD_TYPE __NLINK_T_TYPE __nlink_t; /* Type of file link counts. */ +__STD_TYPE __OFF_T_TYPE __off_t; /* Type of file sizes and offsets. */ +__STD_TYPE __OFF64_T_TYPE __off64_t; /* Type of file sizes and offsets (LFS). */ +__STD_TYPE __PID_T_TYPE __pid_t; /* Type of process identifications. */ +__STD_TYPE __FSID_T_TYPE __fsid_t; /* Type of file system IDs. */ +__STD_TYPE __CLOCK_T_TYPE __clock_t; /* Type of CPU usage counts. */ +__STD_TYPE __RLIM_T_TYPE __rlim_t; /* Type for resource measurement. */ +__STD_TYPE __RLIM64_T_TYPE __rlim64_t; /* Type for resource measurement (LFS). */ +__STD_TYPE __ID_T_TYPE __id_t; /* General type for IDs. */ +__STD_TYPE __TIME_T_TYPE __time_t; /* Seconds since the Epoch. */ +__STD_TYPE __USECONDS_T_TYPE __useconds_t; /* Count of microseconds. */ +__STD_TYPE __SUSECONDS_T_TYPE __suseconds_t; /* Signed count of microseconds. */ + +__STD_TYPE __DADDR_T_TYPE __daddr_t; /* The type of a disk address. */ +__STD_TYPE __KEY_T_TYPE __key_t; /* Type of an IPC key. */ + +/* Clock ID used in clock and timer functions. */ +__STD_TYPE __CLOCKID_T_TYPE __clockid_t; + +/* Timer ID returned by `timer_create'. */ +__STD_TYPE __TIMER_T_TYPE __timer_t; + +/* Type to represent block size. */ +__STD_TYPE __BLKSIZE_T_TYPE __blksize_t; + +/* Types from the Large File Support interface. */ + +/* Type to count number of disk blocks. */ +__STD_TYPE __BLKCNT_T_TYPE __blkcnt_t; +__STD_TYPE __BLKCNT64_T_TYPE __blkcnt64_t; + +/* Type to count file system blocks. */ +__STD_TYPE __FSBLKCNT_T_TYPE __fsblkcnt_t; +__STD_TYPE __FSBLKCNT64_T_TYPE __fsblkcnt64_t; + +/* Type to count file system nodes. */ +__STD_TYPE __FSFILCNT_T_TYPE __fsfilcnt_t; +__STD_TYPE __FSFILCNT64_T_TYPE __fsfilcnt64_t; + +/* Type of miscellaneous file system fields. */ +__STD_TYPE __FSWORD_T_TYPE __fsword_t; + +__STD_TYPE __SSIZE_T_TYPE __ssize_t; /* Type of a byte count, or error. */ + +/* Signed long type used in system calls. */ +__STD_TYPE __SYSCALL_SLONG_TYPE __syscall_slong_t; +/* Unsigned long type used in system calls. */ +__STD_TYPE __SYSCALL_ULONG_TYPE __syscall_ulong_t; + +/* These few don't really vary by system, they always correspond + to one of the other defined types. */ +typedef __off64_t __loff_t; /* Type of file sizes and offsets (LFS). */ +typedef __quad_t *__qaddr_t; +typedef char *__caddr_t; + +/* Duplicates info from stdint.h but this is used in unistd.h. */ +__STD_TYPE __SWORD_TYPE __intptr_t; + +/* Duplicate info from sys/socket.h. */ +__STD_TYPE __U32_TYPE __socklen_t; + +/* C99: An integer type that can be accessed as an atomic entity, + even in the presence of asynchronous interrupts. + It is not currently necessary for this to be machine-specific. */ +typedef int __sig_atomic_t; + +#undef __STD_TYPE + +#endif /* bits/types.h */ diff --git a/REORG.TODO/posix/bits/unistd.h b/REORG.TODO/posix/bits/unistd.h new file mode 100644 index 0000000000..4e4153c94f --- /dev/null +++ b/REORG.TODO/posix/bits/unistd.h @@ -0,0 +1,385 @@ +/* Checking macros for unistd functions. + Copyright (C) 2005-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 ssize_t __REDIRECT (__read_chk_warn, + (int __fd, void *__buf, size_t __nbytes, + size_t __buflen), __read_chk) + __wur __warnattr ("read called with bigger length than size of " + "the destination buffer"); + +__fortify_function __wur ssize_t +read (int __fd, void *__buf, size_t __nbytes) +{ + if (__bos0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) + return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf)); + + if (__nbytes > __bos0 (__buf)) + return __read_chk_warn (__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; +extern ssize_t __REDIRECT (__pread_chk_warn, + (int __fd, void *__buf, size_t __nbytes, + __off_t __offset, size_t __bufsize), __pread_chk) + __wur __warnattr ("pread called with bigger length than size of " + "the destination buffer"); +extern ssize_t __REDIRECT (__pread64_chk_warn, + (int __fd, void *__buf, size_t __nbytes, + __off64_t __offset, size_t __bufsize), + __pread64_chk) + __wur __warnattr ("pread64 called with bigger length than size of " + "the destination buffer"); + +# ifndef __USE_FILE_OFFSET64 +__fortify_function __wur ssize_t +pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) + return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + + if ( __nbytes > __bos0 (__buf)) + return __pread_chk_warn (__fd, __buf, __nbytes, __offset, + __bos0 (__buf)); + } + return __pread_alias (__fd, __buf, __nbytes, __offset); +} +# else +__fortify_function __wur ssize_t +pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) + return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + + if ( __nbytes > __bos0 (__buf)) + return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, + __bos0 (__buf)); + } + + return __pread64_alias (__fd, __buf, __nbytes, __offset); +} +# endif + +# ifdef __USE_LARGEFILE64 +__fortify_function __wur ssize_t +pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) + return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + + if ( __nbytes > __bos0 (__buf)) + return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, + __bos0 (__buf)); + } + + return __pread64_alias (__fd, __buf, __nbytes, __offset); +} +# endif +#endif + +#if 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 ssize_t __REDIRECT_NTH (__readlink_chk_warn, + (const char *__restrict __path, + char *__restrict __buf, size_t __len, + size_t __buflen), __readlink_chk) + __nonnull ((1, 2)) __wur __warnattr ("readlink called with bigger length " + "than size of destination buffer"); + +__fortify_function __nonnull ((1, 2)) __wur ssize_t +__NTH (readlink (const char *__restrict __path, char *__restrict __buf, + size_t __len)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __readlink_chk (__path, __buf, __len, __bos (__buf)); + + if ( __len > __bos (__buf)) + return __readlink_chk_warn (__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 ssize_t __REDIRECT_NTH (__readlinkat_chk_warn, + (int __fd, const char *__restrict __path, + char *__restrict __buf, size_t __len, + size_t __buflen), __readlinkat_chk) + __nonnull ((2, 3)) __wur __warnattr ("readlinkat called with bigger " + "length than size of destination " + "buffer"); + +__fortify_function __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) + { + if (!__builtin_constant_p (__len)) + return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf)); + + if (__len > __bos (__buf)) + return __readlinkat_chk_warn (__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 char *__REDIRECT_NTH (__getcwd_chk_warn, + (char *__buf, size_t __size, size_t __buflen), + __getcwd_chk) + __wur __warnattr ("getcwd caller with bigger length than size of " + "destination buffer"); + +__fortify_function __wur char * +__NTH (getcwd (char *__buf, size_t __size)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__size)) + return __getcwd_chk (__buf, __size, __bos (__buf)); + + if (__size > __bos (__buf)) + return __getcwd_chk_warn (__buf, __size, __bos (__buf)); + } + return __getcwd_alias (__buf, __size); +} + +#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED +extern char *__getwd_chk (char *__buf, size_t buflen) + __THROW __nonnull ((1)) __wur; +extern char *__REDIRECT_NTH (__getwd_warn, (char *__buf), getwd) + __nonnull ((1)) __wur __warnattr ("please use getcwd instead, as getwd " + "doesn't specify buffer size"); + +__fortify_function __nonnull ((1)) __attribute_deprecated__ __wur char * +__NTH (getwd (char *__buf)) +{ + if (__bos (__buf) != (size_t) -1) + return __getwd_chk (__buf, __bos (__buf)); + return __getwd_warn (__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 size_t __REDIRECT_NTH (__confstr_chk_warn, + (int __name, char *__buf, size_t __len, + size_t __buflen), __confstr_chk) + __warnattr ("confstr called with bigger length than size of destination " + "buffer"); + +__fortify_function size_t +__NTH (confstr (int __name, char *__buf, size_t __len)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __confstr_chk (__name, __buf, __len, __bos (__buf)); + + if (__bos (__buf) < __len) + return __confstr_chk_warn (__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 int __REDIRECT_NTH (__getgroups_chk_warn, + (int __size, __gid_t __list[], size_t __listlen), + __getgroups_chk) + __wur __warnattr ("getgroups called with bigger group count than what " + "can fit into destination buffer"); + +__fortify_function int +__NTH (getgroups (int __size, __gid_t __list[])) +{ + if (__bos (__list) != (size_t) -1) + { + if (!__builtin_constant_p (__size) || __size < 0) + return __getgroups_chk (__size, __list, __bos (__list)); + + if (__size * sizeof (__gid_t) > __bos (__list)) + return __getgroups_chk_warn (__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 int __REDIRECT_NTH (__ttyname_r_chk_warn, + (int __fd, char *__buf, size_t __buflen, + size_t __nreal), __ttyname_r_chk) + __nonnull ((2)) __warnattr ("ttyname_r called with bigger buflen than " + "size of destination buffer"); + +__fortify_function int +__NTH (ttyname_r (int __fd, char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) + return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf)); + + if (__buflen > __bos (__buf)) + return __ttyname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf)); + } + return __ttyname_r_alias (__fd, __buf, __buflen); +} + + +#ifdef __USE_POSIX199506 +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 int __REDIRECT (__getlogin_r_chk_warn, + (char *__buf, size_t __buflen, size_t __nreal), + __getlogin_r_chk) + __nonnull ((1)) __warnattr ("getlogin_r called with bigger buflen than " + "size of destination buffer"); + +__fortify_function int +getlogin_r (char *__buf, size_t __buflen) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) + return __getlogin_r_chk (__buf, __buflen, __bos (__buf)); + + if (__buflen > __bos (__buf)) + return __getlogin_r_chk_warn (__buf, __buflen, __bos (__buf)); + } + return __getlogin_r_alias (__buf, __buflen); +} +#endif + + +#if defined __USE_MISC || 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 int __REDIRECT_NTH (__gethostname_chk_warn, + (char *__buf, size_t __buflen, size_t __nreal), + __gethostname_chk) + __nonnull ((1)) __warnattr ("gethostname called with bigger buflen than " + "size of destination buffer"); + +__fortify_function int +__NTH (gethostname (char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) + return __gethostname_chk (__buf, __buflen, __bos (__buf)); + + if (__buflen > __bos (__buf)) + return __gethostname_chk_warn (__buf, __buflen, __bos (__buf)); + } + return __gethostname_alias (__buf, __buflen); +} +#endif + + +#if defined __USE_MISC || (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 int __REDIRECT_NTH (__getdomainname_chk_warn, + (char *__buf, size_t __buflen, size_t __nreal), + __getdomainname_chk) + __nonnull ((1)) __wur __warnattr ("getdomainname called with bigger " + "buflen than size of destination " + "buffer"); + +__fortify_function int +__NTH (getdomainname (char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) + return __getdomainname_chk (__buf, __buflen, __bos (__buf)); + + if (__buflen > __bos (__buf)) + return __getdomainname_chk_warn (__buf, __buflen, __bos (__buf)); + } + return __getdomainname_alias (__buf, __buflen); +} +#endif diff --git a/REORG.TODO/posix/bsd-getpgrp.c b/REORG.TODO/posix/bsd-getpgrp.c new file mode 100644 index 0000000000..b48b7b3d03 --- /dev/null +++ b/REORG.TODO/posix/bsd-getpgrp.c @@ -0,0 +1,31 @@ +/* BSD-compatible versions of getpgrp function. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-ga1.c b/REORG.TODO/posix/bug-ga1.c new file mode 100644 index 0000000000..c46ab43fd1 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-ga2.c b/REORG.TODO/posix/bug-ga2.c new file mode 100644 index 0000000000..5ea759b8ce --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-getopt1.c b/REORG.TODO/posix/bug-getopt1.c new file mode 100644 index 0000000000..a47dc7e229 --- /dev/null +++ b/REORG.TODO/posix/bug-getopt1.c @@ -0,0 +1,73 @@ +/* BZ 11039 */ +#include <unistd.h> +#include <stdio.h> + +static int +one_test (const char *fmt, int argc, char *argv[], int expected[argc - 1]) +{ + optind = 1; + + int res = 0; + for (int i = 0; i < argc - 1; ++i) + { + rewind (stderr); + if (ftruncate (fileno (stderr), 0) != 0) + { + puts ("cannot truncate file"); + return 1; + } + + int c = getopt (argc, argv, fmt); + if (c != expected[i]) + { + printf ("format '%s' test %d failed: expected '%c', got '%c'\n", + fmt, i, expected[i], c); + res = 1; + } + if (ftell (stderr) != 0) + { + printf ("format '%s' test %d failed: printed to stderr\n", + fmt, i); + res = 1; + } + } + + return res; +} + + +static int +do_test (void) +{ + char *fname = tmpnam (NULL); + if (fname == NULL) + { + puts ("cannot generate name for temporary file"); + return 1; + } + + if (freopen (fname, "w+", stderr) == NULL) + { + puts ("cannot redirect stderr"); + return 1; + } + + remove (fname); + + int ret = one_test ("+:a:b", 2, + (char *[2]) { (char *) "bug-getopt1", (char *) "-a" }, + (int [1]) { ':' }); + + ret |= one_test ("+:a:b", 3, + (char *[3]) { (char *) "bug-getopt1", (char *) "-b", + (char *) "-a" }, + (int [2]) { 'b', ':' }); + + if (ret == 0) + puts ("all OK"); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-getopt2.c b/REORG.TODO/posix/bug-getopt2.c new file mode 100644 index 0000000000..93c3035ccd --- /dev/null +++ b/REORG.TODO/posix/bug-getopt2.c @@ -0,0 +1,72 @@ +/* BZ 11039 */ +#include <unistd.h> +#include <stdio.h> + +static int +one_test (const char *fmt, int argc, char *argv[], int expected[argc - 1]) +{ + int res = 0; + for (int i = 0; i < argc - 1; ++i) + { + rewind (stderr); + if (ftruncate (fileno (stderr), 0) != 0) + { + puts ("cannot truncate file"); + return 1; + } + + int c = getopt (argc, argv, fmt); + if (c != expected[i]) + { + printf ("format '%s' test %d failed: expected '%c', got '%c'\n", + fmt, i, expected[i], c); + res = 1; + } + if (ftell (stderr) == 0) + { + printf ("format '%s' test %d failed: not printed to stderr\n", + fmt, i); + res = 1; + } + } + + return res; +} + + +static int +do_test (void) +{ + char *fname = tmpnam (NULL); + if (fname == NULL) + { + puts ("cannot generate name for temporary file"); + return 1; + } + + if (freopen (fname, "w+", stderr) == NULL) + { + puts ("cannot redirect stderr"); + return 1; + } + + remove (fname); + + optind = 0; + int ret = one_test ("+a", 2, + (char *[2]) { (char *) "bug-getopt2", (char *) "-+" }, + (int [1]) { '?' }); + + optind = 1; + ret |= one_test ("+a", 2, + (char *[2]) { (char *) "bug-getopt2", (char *) "-+" }, + (int [1]) { '?' }); + + if (ret == 0) + puts ("all OK"); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-getopt3.c b/REORG.TODO/posix/bug-getopt3.c new file mode 100644 index 0000000000..c3a8cb225b --- /dev/null +++ b/REORG.TODO/posix/bug-getopt3.c @@ -0,0 +1,81 @@ +/* BZ 11040 */ +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> + +static const struct option opts[] = + { + { "alpha", no_argument, NULL, 'a' }, + { "beta", required_argument, NULL, 'b' }, + { NULL, 0, NULL, 0 } + }; + +static int +one_test (const char *fmt, int argc, char *argv[], int n, int expected[n], + int out[n]) +{ + optind = 1; + + int res = 0; + for (int i = 0; i < n; ++i) + { + rewind (stderr); + if (ftruncate (fileno (stderr), 0) != 0) + { + puts ("cannot truncate file"); + return 1; + } + + int c = getopt_long (argc, argv, fmt, opts, NULL); + if (c != expected[i]) + { + printf ("format '%s' test %d failed: expected '%c', got '%c'\n", + fmt, i, expected[i], c); + res = 1; + } + if ((ftell (stderr) != 0) != out[i]) + { + printf ("format '%s' test %d failed: %sprinted to stderr\n", + fmt, i, out[i] ? "not " : ""); + res = 1; + } + } + + return res; +} + + +static int +do_test (void) +{ + char *fname = tmpnam (NULL); + if (fname == NULL) + { + puts ("cannot generate name for temporary file"); + return 1; + } + + if (freopen (fname, "w+", stderr) == NULL) + { + puts ("cannot redirect stderr"); + return 1; + } + + remove (fname); + + int ret = one_test ("ab:W;", 2, + (char *[2]) { (char *) "bug-getopt3", (char *) "-a;" }, + 2, (int [2]) { 'a', '?' }, (int [2]) { 0, 1 }); + + ret |= one_test ("ab:W;", 2, + (char *[2]) { (char *) "bug-getopt3", (char *) "-a:" }, 2, + (int [2]) { 'a', '?' }, (int [2]) { 0, 1 }); + + if (ret == 0) + puts ("all OK"); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-getopt4.c b/REORG.TODO/posix/bug-getopt4.c new file mode 100644 index 0000000000..0956ca57fb --- /dev/null +++ b/REORG.TODO/posix/bug-getopt4.c @@ -0,0 +1,86 @@ +/* BZ 11041 */ +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> + +static const struct option opts[] = + { + { "alpha", optional_argument, NULL, 'a' }, + { NULL, 0, NULL, 0 } + }; + +static int +one_test (const char *fmt, int argc, char *argv[], int n, int expected[n]) +{ + optind = 1; + + int res = 0; + for (int i = 0; i < n; ++i) + { + rewind (stderr); + if (ftruncate (fileno (stderr), 0) != 0) + { + puts ("cannot truncate file"); + return 1; + } + + int c = getopt_long (argc, argv, fmt, opts, NULL); + if (c != expected[i]) + { + printf ("%s: format '%s' test %d failed: expected '%c', got '%c'\n", + argv[0], fmt, i, expected[i], c); + res = 1; + } + else if (optarg != NULL) + { + printf ("%s: format '%s' test %d failed: optarg is \"%s\", not NULL\n", + argv[0], fmt, i, optarg); + res = 1; + } + if (ftell (stderr) != 0) + { + printf ("%s: format '%s' test %d failed: printed to stderr\n", + argv[0], fmt, i); + res = 1; + } + } + + return res; +} + + +static int +do_test (void) +{ + char *fname = tmpnam (NULL); + if (fname == NULL) + { + puts ("cannot generate name for temporary file"); + return 1; + } + + if (freopen (fname, "w+", stderr) == NULL) + { + puts ("cannot redirect stderr"); + return 1; + } + + remove (fname); + + int ret = one_test ("W;", 2, + (char *[2]) { (char *) "bug-getopt4a", (char *) "--a" }, + 1, (int [1]) { 'a' }); + + ret |= one_test ("W;", 3, + (char *[3]) { (char *) "bug-getopt4b", (char *) "-W", + (char *) "a" }, + 1, (int [1]) { 'a' }); + + if (ret == 0) + puts ("all OK"); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-getopt5.c b/REORG.TODO/posix/bug-getopt5.c new file mode 100644 index 0000000000..ed2639d35b --- /dev/null +++ b/REORG.TODO/posix/bug-getopt5.c @@ -0,0 +1,81 @@ +/* BZ 11041 */ +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> + +static const struct option opts[] = + { + { "a1", no_argument, NULL, 'a' }, + { "a2", no_argument, NULL, 'a' }, + { NULL, 0, NULL, 0 } + }; + +static int +one_test (const char *fmt, int argc, char *argv[], int n, int expected[n]) +{ + optind = 1; + + int res = 0; + for (int i = 0; i < n; ++i) + { + rewind (stderr); + if (ftruncate (fileno (stderr), 0) != 0) + { + puts ("cannot truncate file"); + return 1; + } + + int c = getopt_long (argc, argv, fmt, opts, NULL); + if (c != expected[i]) + { + printf ("format '%s' test %d failed: expected '%c', got '%c'\n", + fmt, i, expected[i], c); + res = 1; + } + if (ftell (stderr) != 0) + { + printf ("format '%s' test %d failed: printed to stderr\n", + fmt, i); + res = 1; + } + } + + return res; +} + + +static int +do_test (void) +{ + char *fname = tmpnam (NULL); + if (fname == NULL) + { + puts ("cannot generate name for temporary file"); + return 1; + } + + if (freopen (fname, "w+", stderr) == NULL) + { + puts ("cannot redirect stderr"); + return 1; + } + + remove (fname); + + int ret = one_test (":W;", 2, + (char *[2]) { (char *) "bug-getopt5", (char *) "--a" }, + 1, (int [1]) { 'a' }); + + ret |= one_test (":W;", 3, + (char *[3]) { (char *) "bug-getopt5", (char *) "-W", + (char *) "a" }, + 1, (int [1]) { 'a' }); + + if (ret == 0) + puts ("all OK"); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-glob1.c b/REORG.TODO/posix/bug-glob1.c new file mode 100644 index 0000000000..05c2da7584 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-glob2.c b/REORG.TODO/posix/bug-glob2.c new file mode 100644 index 0000000000..592d957a75 --- /dev/null +++ b/REORG.TODO/posix/bug-glob2.c @@ -0,0 +1,314 @@ +/* Test glob memory management. + for the filesystem access functions. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 + +#define LONG_NAME \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +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 }, + { LONG_NAME, 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[sizeof (LONG_NAME)]; +} 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 = 1; /* glob should not skip this entry. */ + +#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/REORG.TODO/posix/bug-glob3.c b/REORG.TODO/posix/bug-glob3.c new file mode 100644 index 0000000000..f2fbd703dd --- /dev/null +++ b/REORG.TODO/posix/bug-glob3.c @@ -0,0 +1,45 @@ +#include <glob.h> +#include <stdio.h> +#include <string.h> + +static int +do_test (void) +{ + int result = 0; + glob_t g; + g.gl_pathc = 0; + + int r = glob ("", 0, NULL, &g); + if (r != GLOB_NOMATCH) + { + puts ("glob (\"\", 0, NULL, &g) did not fail"); + result = 1; + } + else if (g.gl_pathc != 0) + { + puts ("gl_pathc after glob (\"\", 0, NULL, &g) not zero"); + result = 1; + } + + r = glob ("", GLOB_NOCHECK, NULL, &g); + if (r != 0) + { + puts ("glob (\"\", GLOB_NOCHECK, NULL, &g) did fail"); + result = 1; + } + else if (g.gl_pathc != 1) + { + puts ("gl_pathc after glob (\"\", GLOB_NOCHECK, NULL, &g) not 1"); + result = 1; + } + else if (strcmp (g.gl_pathv[0], "") != 0) + { + puts ("gl_pathv[0] after glob (\"\", GLOB_NOCHECK, NULL, &g) not \"\""); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex1.c b/REORG.TODO/posix/bug-regex1.c new file mode 100644 index 0000000000..38eb543951 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-regex10.c b/REORG.TODO/posix/bug-regex10.c new file mode 100644 index 0000000000..1d47487479 --- /dev/null +++ b/REORG.TODO/posix/bug-regex10.c @@ -0,0 +1,60 @@ +/* Test for re_match with non-zero start. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex11.c b/REORG.TODO/posix/bug-regex11.c new file mode 100644 index 0000000000..9a4f9ac319 --- /dev/null +++ b/REORG.TODO/posix/bug-regex11.c @@ -0,0 +1,138 @@ +/* Regular expression tests. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex12.c b/REORG.TODO/posix/bug-regex12.c new file mode 100644 index 0000000000..d0b47499a8 --- /dev/null +++ b/REORG.TODO/posix/bug-regex12.c @@ -0,0 +1,72 @@ +/* Regular expression tests. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex13.c b/REORG.TODO/posix/bug-regex13.c new file mode 100644 index 0000000000..bff48ca9ad --- /dev/null +++ b/REORG.TODO/posix/bug-regex13.c @@ -0,0 +1,102 @@ +/* Regular expression tests. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex14.c b/REORG.TODO/posix/bug-regex14.c new file mode 100644 index 0000000000..45f1273d52 --- /dev/null +++ b/REORG.TODO/posix/bug-regex14.c @@ -0,0 +1,53 @@ +/* Tests re_comp and re_exec. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex15.c b/REORG.TODO/posix/bug-regex15.c new file mode 100644 index 0000000000..8f6d3cc00d --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-regex16.c b/REORG.TODO/posix/bug-regex16.c new file mode 100644 index 0000000000..1e41ccb718 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-regex17.c b/REORG.TODO/posix/bug-regex17.c new file mode 100644 index 0000000000..72a4d5cf7a --- /dev/null +++ b/REORG.TODO/posix/bug-regex17.c @@ -0,0 +1,109 @@ +/* German regular expression tests. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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[] = { + /* U+00C4 \xc3\x84 LATIN CAPITAL LETTER A WITH DIAERESIS + U+00D6 \xc3\x96 LATIN CAPITAL LETTER O WITH DIAERESIS + U+00E4 \xc3\xa4 LATIN SMALL LETTER A WITH DIAERESIS + U+00F6 \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 } } }, + + /* Tests for bug 9697: + U+00DF \xc3\x9f LATIN SMALL LETTER SHARP S + U+02DA \xcb\x9a RING ABOVE + U+02E2 \xcb\xa2 MODIFIER LETTER SMALL S */ + { "[a-z]|[^a-z]", "\xcb\xa2", REG_EXTENDED, 2, + { { 0, 2 }, { -1, -1 } } }, + { "[a-z]", "\xc3\x9f", REG_EXTENDED, 2, + { { 0, 2 }, { -1, -1 } } }, + { "[^a-z]", "\xcb\x9a", REG_EXTENDED, 2, + { { 0, 2 }, { -1, -1 } } }, +}; + + +static int +do_test (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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex18.c b/REORG.TODO/posix/bug-regex18.c new file mode 100644 index 0000000000..55c266c82b --- /dev/null +++ b/REORG.TODO/posix/bug-regex18.c @@ -0,0 +1,99 @@ +/* Turkish regular expression tests. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex19.c b/REORG.TODO/posix/bug-regex19.c new file mode 100644 index 0000000000..7f8b9fe3a1 --- /dev/null +++ b/REORG.TODO/posix/bug-regex19.c @@ -0,0 +1,417 @@ +/* Regular expression tests. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex2.c b/REORG.TODO/posix/bug-regex2.c new file mode 100644 index 0000000000..f32d8d3da1 --- /dev/null +++ b/REORG.TODO/posix/bug-regex2.c @@ -0,0 +1,53 @@ +/* Test for memory handling in regex. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex20.c b/REORG.TODO/posix/bug-regex20.c new file mode 100644 index 0000000000..90d10d0690 --- /dev/null +++ b/REORG.TODO/posix/bug-regex20.c @@ -0,0 +1,286 @@ +/* Test for UTF-8 regular expression optimizations. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex21.c b/REORG.TODO/posix/bug-regex21.c new file mode 100644 index 0000000000..3e90385b69 --- /dev/null +++ b/REORG.TODO/posix/bug-regex21.c @@ -0,0 +1,44 @@ +/* Test for memory leaks in regcomp. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex22.c b/REORG.TODO/posix/bug-regex22.c new file mode 100644 index 0000000000..a03ec1336f --- /dev/null +++ b/REORG.TODO/posix/bug-regex22.c @@ -0,0 +1,118 @@ +/* Test re.translate != NULL. + Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex23.c b/REORG.TODO/posix/bug-regex23.c new file mode 100644 index 0000000000..8d3a9a67e9 --- /dev/null +++ b/REORG.TODO/posix/bug-regex23.c @@ -0,0 +1,34 @@ +/* Test we don't segfault on invalid UTF-8 sequence. + Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex24.c b/REORG.TODO/posix/bug-regex24.c new file mode 100644 index 0000000000..97c5c3508a --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/bug-regex25.c b/REORG.TODO/posix/bug-regex25.c new file mode 100644 index 0000000000..384df305ad --- /dev/null +++ b/REORG.TODO/posix/bug-regex25.c @@ -0,0 +1,56 @@ +/* Test re_search in multibyte locale other than UTF-8. + Copyright (C) 2006-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex26.c b/REORG.TODO/posix/bug-regex26.c new file mode 100644 index 0000000000..7237be8967 --- /dev/null +++ b/REORG.TODO/posix/bug-regex26.c @@ -0,0 +1,37 @@ +/* Test re_search with dotless i. + Copyright (C) 2006-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <locale.h> +#include <regex.h> +#include <string.h> + +int +main (void) +{ + struct re_pattern_buffer r; + struct re_registers s; + setlocale (LC_ALL, "en_US.UTF-8"); + memset (&r, 0, sizeof (r)); + memset (&s, 0, sizeof (s)); + re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | RE_ICASE); + re_compile_pattern ("insert into", 11, &r); + re_search (&r, "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK", + 15, 0, 15, &s); + return 0; +} diff --git a/REORG.TODO/posix/bug-regex27.c b/REORG.TODO/posix/bug-regex27.c new file mode 100644 index 0000000000..118dc00c0a --- /dev/null +++ b/REORG.TODO/posix/bug-regex27.c @@ -0,0 +1,63 @@ +/* Test REG_NEWLINE. + Copyright (C) 2007-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <regex.h> +#include <stdio.h> +#include <string.h> + +struct tests +{ + const char *regex; + const char *string; + int cflags; + int retval; +} tests[] = { + { "a.b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH }, + { "a.b", "a\nb", REG_EXTENDED, 0 }, + { "a[^x]b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH }, + { "a[^x]b", "a\nb", REG_EXTENDED, 0 } +}; + +int +main (void) +{ + regex_t r; + size_t i; + int ret = 0; + + for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i) + { + memset (&r, 0, sizeof (r)); + if (regcomp (&r, tests[i].regex, tests[i].cflags)) + { + printf ("regcomp %zd failed\n", i); + ret = 1; + continue; + } + int rv = regexec (&r, tests[i].string, 0, NULL, 0); + if (rv != tests[i].retval) + { + printf ("regexec %zd unexpected value %d != %d\n", + i, rv, tests[i].retval); + ret = 1; + } + regfree (&r); + } + return ret; +} diff --git a/REORG.TODO/posix/bug-regex28.c b/REORG.TODO/posix/bug-regex28.c new file mode 100644 index 0000000000..338d97ca34 --- /dev/null +++ b/REORG.TODO/posix/bug-regex28.c @@ -0,0 +1,74 @@ +/* Test RE_HAT_LISTS_NOT_NEWLINE and RE_DOT_NEWLINE. + Copyright (C) 2007-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <regex.h> +#include <stdio.h> +#include <string.h> + +struct tests +{ + const char *regex; + const char *string; + reg_syntax_t syntax; + int retval; +} tests[] = { +#define EGREP RE_SYNTAX_EGREP +#define EGREP_NL (RE_SYNTAX_EGREP | RE_DOT_NEWLINE) & ~RE_HAT_LISTS_NOT_NEWLINE + { "a.b", "a\nb", EGREP, -1 }, + { "a.b", "a\nb", EGREP_NL, 0 }, + { "a[^x]b", "a\nb", EGREP, -1 }, + { "a[^x]b", "a\nb", EGREP_NL, 0 }, + /* While \S and \W are internally handled as [^[:space:]] and [^[:alnum:]_], + RE_HAT_LISTS_NOT_NEWLINE did not make any difference, so ensure + it doesn't change. */ + { "a\\Sb", "a\nb", EGREP, -1 }, + { "a\\Sb", "a\nb", EGREP_NL, -1 }, + { "a\\Wb", "a\nb", EGREP, 0 }, + { "a\\Wb", "a\nb", EGREP_NL, 0 } +}; + +int +main (void) +{ + struct re_pattern_buffer r; + size_t i; + int ret = 0; + + for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i) + { + re_set_syntax (tests[i].syntax); + memset (&r, 0, sizeof (r)); + if (re_compile_pattern (tests[i].regex, strlen (tests[i].regex), &r)) + { + printf ("re_compile_pattern %zd failed\n", i); + ret = 1; + continue; + } + size_t len = strlen (tests[i].string); + int rv = re_search (&r, tests[i].string, len, 0, len, NULL); + if (rv != tests[i].retval) + { + printf ("re_search %zd unexpected value %d != %d\n", + i, rv, tests[i].retval); + ret = 1; + } + regfree (&r); + } + return ret; +} diff --git a/REORG.TODO/posix/bug-regex29.c b/REORG.TODO/posix/bug-regex29.c new file mode 100644 index 0000000000..cfc9f99dbc --- /dev/null +++ b/REORG.TODO/posix/bug-regex29.c @@ -0,0 +1,23 @@ +#include <regex.h> +#include <stdio.h> + +static int +do_test (void) +{ + regex_t r; + int e = regcomp(&r, "xy\\{4,5,7\\}zabc", 0); + char buf[100]; + regerror(e, &r, buf, sizeof (buf)); + printf ("e = %d (%s)\n", e, buf); + int res = e != REG_BADBR; + + e = regcomp(&r, "xy\\{4,5a\\}zabc", 0); + regerror(e, &r, buf, sizeof (buf)); + printf ("e = %d (%s)\n", e, buf); + res |= e != REG_BADBR; + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex3.c b/REORG.TODO/posix/bug-regex3.c new file mode 100644 index 0000000000..7156ea422d --- /dev/null +++ b/REORG.TODO/posix/bug-regex3.c @@ -0,0 +1,44 @@ +/* Test for case handling in regex. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex30.c b/REORG.TODO/posix/bug-regex30.c new file mode 100644 index 0000000000..74a35e5fb5 --- /dev/null +++ b/REORG.TODO/posix/bug-regex30.c @@ -0,0 +1,102 @@ +/* Russian regular expression tests. + Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paolo Bonzini <pbonzini@redhat.com>, 2009. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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[] = { + /* U+0413 \xd0\x93 CYRILLIC CAPITAL LETTER GHE + U+0420 \xd0\xa0 CYRILLIC CAPITAL LETTER ER + U+0430 \xd0\xb0 CYRILLIC SMALL LETTER A + U+0433 \xd0\xb3 CYRILLIC SMALL LETTER GHE + U+0440 \xd1\x80 CYRILLIC SMALL LETTER ER + U+044F \xd1\x8f CYRILLIC SMALL LETTER YA */ + { "[\xd0\xb0-\xd1\x8f]", "\xd0\xb3", 0, 1, + { { 0, 2 } } }, + { "[\xd0\xb0-\xd1\x8f]", "\xd0\x93", REG_ICASE, 1, + { { 0, 2 } } }, + { "[\xd1\x80-\xd1\x8f]", "\xd0\xa0", REG_ICASE, 1, + { { 0, 2 } } }, +}; + + +static int +do_test (void) +{ + if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL) + { + puts ("setlocale failed"); + return 1; + } + + int ret = 0; + + for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i) + { + regex_t re; + regmatch_t rm[5]; + int 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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex31.c b/REORG.TODO/posix/bug-regex31.c new file mode 100644 index 0000000000..fd7e0c57ca --- /dev/null +++ b/REORG.TODO/posix/bug-regex31.c @@ -0,0 +1,37 @@ +#include <mcheck.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +int +main (void) +{ + mtrace (); + + int res = 0; + char *buf = NULL; + size_t len = 0; + while (! feof (stdin)) + { + ssize_t n = getline (&buf, &len, stdin); + if (n <= 0) + break; + if (buf[n - 1] == '\n') + buf[n - 1] = '\0'; + + regex_t regex; + int rc = regcomp (®ex, buf, REG_EXTENDED); + if (rc != 0) + printf ("%s: Error %d (expected)\n", buf, rc); + else + { + printf ("%s: succeeded !\n", buf); + res = 1; + } + } + + free (buf); + + return res; +} diff --git a/REORG.TODO/posix/bug-regex31.input b/REORG.TODO/posix/bug-regex31.input new file mode 100644 index 0000000000..3d1f531f4e --- /dev/null +++ b/REORG.TODO/posix/bug-regex31.input @@ -0,0 +1,4 @@ +[[][ +([0] +([0]a +([0]([0]) diff --git a/REORG.TODO/posix/bug-regex32.c b/REORG.TODO/posix/bug-regex32.c new file mode 100644 index 0000000000..525232c69b --- /dev/null +++ b/REORG.TODO/posix/bug-regex32.c @@ -0,0 +1,36 @@ +// BZ 12811 +#include <regex.h> +#include <stdio.h> +#include <locale.h> + +static int +do_test (void) +{ + char buf[1000]; + regex_t preg; + if (setlocale (LC_CTYPE, "de_DE.UTF-8") == NULL) + { + puts ("setlocale failed"); + return 1; + } + + int e = regcomp (&preg, ".*ab", REG_ICASE); + if (e != 0) + { + regerror (e, &preg, buf, sizeof (buf)); + printf ("regcomp = %d \"%s\"\n", e, buf); + return 1; + } + + // Incomplete character at the end of the buffer + e = regexec (&preg, "aaaaaaaaaaaa\xc4", 0, NULL, 0); + + regfree (&preg); + regerror (e, &preg, buf, sizeof (buf)); + printf ("regexec = %d \"%s\"\n", e, buf); + + return e != REG_NOMATCH; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex33.c b/REORG.TODO/posix/bug-regex33.c new file mode 100644 index 0000000000..a34c6549d2 --- /dev/null +++ b/REORG.TODO/posix/bug-regex33.c @@ -0,0 +1,119 @@ +/* Test re_search with multi-byte characters in EUC-JP. + Copyright (C) 2012-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Stanislav Brabec <sbrabec@suse.cz>, 2012. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE 1 +#include <locale.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "regex_internal.h" + +static int +do_test (void) +{ + struct re_pattern_buffer r; + struct re_registers s; + int e, rc = 0; + if (setlocale (LC_CTYPE, "ja_JP.EUC-JP") == NULL) + { + puts ("setlocale failed"); + return 1; + } + memset (&r, 0, sizeof (r)); + memset (&s, 0, sizeof (s)); + + /* The bug cannot be reproduced without initialized fastmap. */ + r.fastmap = malloc (SBC_MAX); + + /* åœ */ + re_compile_pattern ("\xb7\xbd", 2, &r); + + /* aaaaa件a新処, \xb7\xbd constitutes a false match */ + e = re_search (&r, "\x61\x61\x61\x61\x61\xb7\xef\x61\xbf\xb7\xbd\xe8", + 12, 0, 12, &s); + if (e != -1) + { + printf ("bug-regex33.1: false match or error: re_search() returned %d, should return -1\n", e); + rc = 1; + } + + /* aaaa件a新処, \xb7\xbd constitutes a false match, + * this is a reproducer of BZ #13637 */ + e = re_search (&r, "\x61\x61\x61\x61\xb7\xef\x61\xbf\xb7\xbd\xe8", + 11, 0, 11, &s); + if (e != -1) + { + printf ("bug-regex33.2: false match or error: re_search() returned %d, should return -1\n", e); + rc = 1; + } + + /* aaa件a新処, \xb7\xbd constitutes a false match, + * this is a reproducer of BZ #13637 */ + e = re_search (&r, "\x61\x61\x61\xb7\xef\x61\xbf\xb7\xbd\xe8", + 10, 0, 10, &s); + if (e != -1) + { + printf ("bug-regex33.3: false match or error: re_search() returned %d, should return -1\n", e); + rc = 1; + } + + /* aa件a新処, \xb7\xbd constitutes a false match */ + e = re_search (&r, "\x61\x61\xb7\xef\x61\xbf\xb7\xbd\xe8", + 9, 0, 9, &s); + if (e != -1) + { + printf ("bug-regex33.4: false match or error: re_search() returned %d, should return -1\n", e); + rc = 1; + } + + /* a件a新処, \xb7\xbd constitutes a false match */ + e = re_search (&r, "\x61\xb7\xef\x61\xbf\xb7\xbd\xe8", + 8, 0, 8, &s); + if (e != -1) + { + printf ("bug-regex33.5: false match or error: re_search() returned %d, should return -1\n", e); + rc = 1; + } + + /* 新処åœæ–°å‡¦, \xb7\xbd here really matches åœ, but second occurrence is a false match, + * this is a reproducer of bug-regex25 and BZ #13637 */ + e = re_search (&r, "\xbf\xb7\xbd\xe8\xb7\xbd\xbf\xb7\xbd\xe8", + 10, 0, 10, &s); + if (e != 4) + { + printf ("bug-regex33.6: no match or false match: re_search() returned %d, should return 4\n", e); + rc = 1; + } + + /* 新処åœæ–°, \xb7\xbd here really matches åœ, + * this is a reproducer of bug-regex25 */ + e = re_search (&r, "\xbf\xb7\xbd\xe8\xb7\xbd\xbf\xb7", + 10, 0, 10, &s); + if (e != 4) + { + printf ("bug-regex33.7: no match or false match: re_search() returned %d, should return 4\n", e); + rc = 1; + } + + return rc; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex34.c b/REORG.TODO/posix/bug-regex34.c new file mode 100644 index 0000000000..bea1fd9704 --- /dev/null +++ b/REORG.TODO/posix/bug-regex34.c @@ -0,0 +1,46 @@ +/* Test re_search with multi-byte characters in UTF-8. + Copyright (C) 2013-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE 1 +#include <stdio.h> +#include <string.h> +#include <locale.h> +#include <regex.h> + +static int +do_test (void) +{ + struct re_pattern_buffer r; + /* ကျွန်ုပ်x */ + const char *s = "\xe1\x80\x80\xe1\x80\xbb\xe1\x80\xbd\xe1\x80\x94\xe1\x80\xba\xe1\x80\xaf\xe1\x80\x95\xe1\x80\xbax"; + + if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) + { + puts ("setlocale failed"); + return 1; + } + memset (&r, 0, sizeof (r)); + + re_compile_pattern ("[^x]x", 5, &r); + /* This was triggering a buffer overflow. */ + re_search (&r, s, strlen (s), 0, strlen (s), 0); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex35.c b/REORG.TODO/posix/bug-regex35.c new file mode 100644 index 0000000000..6ee0660307 --- /dev/null +++ b/REORG.TODO/posix/bug-regex35.c @@ -0,0 +1,52 @@ +/* Test regcomp with collating symbols in bracket expressions + Copyright (C) 2013-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <string.h> +#include <locale.h> +#include <regex.h> + +static int +do_test (void) +{ + regex_t r; + + if (setlocale (LC_ALL, "cs_CZ.UTF-8") == NULL) + { + puts ("setlocale failed"); + return 1; + } + + if (regcomp (&r, "[[.ch.]]", REG_NOSUB) != 0) + { + puts ("regcomp failed"); + return 1; + } + + if (regexec (&r, "ch", 0, 0, 0) != 0) + { + puts ("regexec failed"); + return 1; + } + + regfree (&r); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/bug-regex36.c b/REORG.TODO/posix/bug-regex36.c new file mode 100644 index 0000000000..442c7657b7 --- /dev/null +++ b/REORG.TODO/posix/bug-regex36.c @@ -0,0 +1,29 @@ +/* Test regcomp not leaking memory on parse errors + Copyright (C) 2014-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <mcheck.h> +#include <regex.h> + +int +main (int argc, char **argv) +{ + regex_t r; + mtrace (); + regcomp (&r, "[a]\\|[a]\\{-2,}", 0); + regfree (&r); +} diff --git a/REORG.TODO/posix/bug-regex4.c b/REORG.TODO/posix/bug-regex4.c new file mode 100644 index 0000000000..fdf1c27f53 --- /dev/null +++ b/REORG.TODO/posix/bug-regex4.c @@ -0,0 +1,59 @@ +/* Test for re_search_2. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex5.c b/REORG.TODO/posix/bug-regex5.c new file mode 100644 index 0000000000..fd18b19df4 --- /dev/null +++ b/REORG.TODO/posix/bug-regex5.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <string.h> +#include <stdint.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/REORG.TODO/posix/bug-regex6.c b/REORG.TODO/posix/bug-regex6.c new file mode 100644 index 0000000000..615b3e1e44 --- /dev/null +++ b/REORG.TODO/posix/bug-regex6.c @@ -0,0 +1,75 @@ +/* Test for regexec. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex7.c b/REORG.TODO/posix/bug-regex7.c new file mode 100644 index 0000000000..157ffffb82 --- /dev/null +++ b/REORG.TODO/posix/bug-regex7.c @@ -0,0 +1,91 @@ +/* Test for regs allocation in re_search and re_match. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex8.c b/REORG.TODO/posix/bug-regex8.c new file mode 100644 index 0000000000..a2cb7e623d --- /dev/null +++ b/REORG.TODO/posix/bug-regex8.c @@ -0,0 +1,83 @@ +/* Test for the STOP parameter of re_match_2 and re_search_2. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/bug-regex9.c b/REORG.TODO/posix/bug-regex9.c new file mode 100644 index 0000000000..a94e44f5c4 --- /dev/null +++ b/REORG.TODO/posix/bug-regex9.c @@ -0,0 +1,66 @@ +/* Test for memory handling in regex. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/confstr.c b/REORG.TODO/posix/confstr.c new file mode 100644 index 0000000000..159a55788e --- /dev/null +++ b/REORG.TODO/posix/confstr.c @@ -0,0 +1,292 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <confstr.h> +#include "../version.h" + +#define NEED_SPEC_ARRAY 0 +#include <posix-conf-vars.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 (int name, char *buf, size_t len) +{ + const char *string = ""; + size_t string_len = 1; + + /* Note that this buffer must be large enough for the longest strings + used below. */ + char restenvs[4 * sizeof "POSIX_V7_LPBIG_OFFBIG"]; + + switch (name) + { + case _CS_PATH: + { + static const char cs_path[] = CS_PATH; + string = cs_path; + string_len = sizeof (cs_path); + } + break; + + /* For _CS_V7_WIDTH_RESTRICTED_ENVS, _CS_V6_WIDTH_RESTRICTED_ENVS + and _CS_V5_WIDTH_RESTRICTED_ENVS: + + We have to return a newline-separated list of names of + programming environments 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 environments that the system allows. */ + +#define START_ENV_GROUP(VERSION) \ + case _CS_##VERSION##_WIDTH_RESTRICTED_ENVS: \ + string_len = 0; + +#define END_ENV_GROUP(VERSION) \ + restenvs[string_len++] = '\0'; \ + string = restenvs; \ + break; + +#define KNOWN_ABSENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + /* Empty. */ + +#define KNOWN_PRESENT_ENV_STRING(STR) \ + if (string_len > 0) \ + restenvs[string_len++] = '\n'; \ + memcpy (restenvs + string_len, STR, \ + sizeof STR - 1); \ + string_len += sizeof STR - 1; + +#define KNOWN_PRESENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + KNOWN_PRESENT_ENV_STRING (#ENV_PREFIX "_" #SUFFIX) + +#define UNKNOWN_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + if (__sysconf (_SC_##SC_PREFIX##_##SUFFIX) > 0) \ + { \ + KNOWN_PRESENT_ENVIRONMENT (SC_PREFIX, ENV_PREFIX, SUFFIX) \ + } + +#include "posix-envs.def" + +#undef START_ENV_GROUP +#undef END_ENV_GROUP +#undef KNOWN_ABSENT_ENVIRONMENT +#undef KNOWN_PRESENT_ENV_STRING +#undef KNOWN_PRESENT_ENVIRONMENT +#undef UNKNOWN_ENVIRONMENT + + case _CS_XBS5_ILP32_OFF32_CFLAGS: + case _CS_POSIX_V6_ILP32_OFF32_CFLAGS: + case _CS_POSIX_V7_ILP32_OFF32_CFLAGS: +#ifdef __ILP32_OFF32_CFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFF32) +# error "__ILP32_OFF32_CFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFF32) + if (__sysconf (_SC_V7_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: + case _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: +#ifdef __ILP32_OFFBIG_CFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFFBIG) +# error "__ILP32_OFFBIG_CFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFFBIG) + if (__sysconf (_SC_V7_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: + case _CS_POSIX_V7_LP64_OFF64_CFLAGS: +#ifdef __LP64_OFF64_CFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_LP64_OFF64) +# error "__LP64_OFF64_CFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_LP64_OFF64) + if (__sysconf (_SC_V7_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: + case _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: +#ifdef __ILP32_OFF32_LDFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFF32 ) +# error "__ILP32_OFF32_LDFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFF32) + if (__sysconf (_SC_V7_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: + case _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: +#ifdef __ILP32_OFFBIG_LDFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFFBIG) +# error "__ILP32_OFFBIG_LDFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFFBIG) + if (__sysconf (_SC_V7_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: + case _CS_POSIX_V7_LP64_OFF64_LDFLAGS: +#ifdef __LP64_OFF64_LDFLAGS +# if CONF_IS_DEFINED_UNSET (_POSIX_V7_LP64_OFF64) +# error "__LP64_OFF64_LDFLAGS should not be defined" +# elif CONF_IS_UNDEFINED (_POSIX_V7_LP64_OFF64) + if (__sysconf (_SC_V7_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 (CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFF32) \ + && CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFFBIG)) +# 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: + + case _CS_POSIX_V7_ILP32_OFF32_LIBS: + case _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: + case _CS_POSIX_V7_ILP32_OFFBIG_LIBS: + case _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: + case _CS_POSIX_V7_LP64_OFF64_LIBS: + case _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: + case _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: + case _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: + case _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: + case _CS_POSIX_V7_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 + + case _CS_V6_ENV: + case _CS_V7_ENV: + /* Maybe something else is needed in future. */ + string = "POSIXLY_CORRECT=1"; + string_len = sizeof ("POSIXLY_CORRECT=1"); + break; + + 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/REORG.TODO/posix/cpio.h b/REORG.TODO/posix/cpio.h new file mode 100644 index 0000000000..f2031016f6 --- /dev/null +++ b/REORG.TODO/posix/cpio.h @@ -0,0 +1,73 @@ +/* Extended cpio format from POSIX.1. + This file is part of the GNU C Library. + Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/environ.c b/REORG.TODO/posix/environ.c new file mode 100644 index 0000000000..a0ed0d80ea --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/execl.c b/REORG.TODO/posix/execl.c new file mode 100644 index 0000000000..4cd0f054e8 --- /dev/null +++ b/REORG.TODO/posix/execl.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <errno.h> +#include <stdarg.h> +#include <sys/param.h> + +/* Execute PATH with all arguments after PATH until + a NULL pointer and environment from `environ'. */ +int +execl (const char *path, const char *arg, ...) +{ + ptrdiff_t argc; + va_list ap; + va_start (ap, arg); + for (argc = 1; va_arg (ap, const char *); argc++) + { + if (argc == INT_MAX) + { + va_end (ap); + errno = E2BIG; + return -1; + } + } + va_end (ap); + + /* Avoid dynamic memory allocation due two main issues: + 1. The function should be async-signal-safe and a running on a signal + handler with a fail outcome might lead to malloc bad state. + 2. It might be used in a vfork/clone(VFORK) scenario where using + malloc also might lead to internal bad state. */ + ptrdiff_t i; + char *argv[argc + 1]; + va_start (ap, arg); + argv[0] = (char *) arg; + for (i = 1; i <= argc; i++) + argv[i] = va_arg (ap, char *); + va_end (ap); + + return __execve (path, argv, __environ); +} +libc_hidden_def (execl) diff --git a/REORG.TODO/posix/execle.c b/REORG.TODO/posix/execle.c new file mode 100644 index 0000000000..bb2c4a0cf2 --- /dev/null +++ b/REORG.TODO/posix/execle.c @@ -0,0 +1,59 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/param.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, ...) +{ + ptrdiff_t argc; + va_list ap; + va_start (ap, arg); + for (argc = 1; va_arg (ap, const char *); argc++) + { + if (argc == INT_MAX) + { + va_end (ap); + errno = E2BIG; + return -1; + } + } + va_end (ap); + + /* Avoid dynamic memory allocation due two main issues: + 1. The function should be async-signal-safe and a running on a signal + handler with a fail outcome might lead to malloc bad state. + 2. It might be used in a vfork/clone(VFORK) scenario where using + malloc also might lead to internal bad state. */ + ptrdiff_t i; + char *argv[argc + 1]; + char **envp; + va_start (ap, arg); + argv[0] = (char *) arg; + for (i = 1; i <= argc; i++) + argv[i] = va_arg (ap, char *); + envp = va_arg (ap, char **); + va_end (ap); + + return __execve (path, argv, envp); +} +libc_hidden_def (execle) diff --git a/REORG.TODO/posix/execlp.c b/REORG.TODO/posix/execlp.c new file mode 100644 index 0000000000..9ea6a2803d --- /dev/null +++ b/REORG.TODO/posix/execlp.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/param.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, ...) +{ + ptrdiff_t argc; + va_list ap; + va_start (ap, arg); + for (argc = 1; va_arg (ap, const char *); argc++) + { + if (argc == INT_MAX) + { + va_end (ap); + errno = E2BIG; + return -1; + } + } + va_end (ap); + + /* Although posix does not state execlp as an async-safe function + it can not use malloc to allocate the arguments since it might + be used in a vfork scenario and it may lead to malloc internal + bad state. */ + ptrdiff_t i; + char *argv[argc + 1]; + va_start (ap, arg); + argv[0] = (char *) arg; + for (i = 1; i <= argc; i++) + argv[i] = va_arg (ap, char *); + va_end (ap); + + return __execvpe (file, argv, __environ); +} +libc_hidden_def (execlp) diff --git a/REORG.TODO/posix/execv.c b/REORG.TODO/posix/execv.c new file mode 100644 index 0000000000..e98895f85a --- /dev/null +++ b/REORG.TODO/posix/execv.c @@ -0,0 +1,26 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/execve.c b/REORG.TODO/posix/execve.c new file mode 100644 index 0000000000..a8b858de06 --- /dev/null +++ b/REORG.TODO/posix/execve.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (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) diff --git a/REORG.TODO/posix/execvp.c b/REORG.TODO/posix/execvp.c new file mode 100644 index 0000000000..68efbead55 --- /dev/null +++ b/REORG.TODO/posix/execvp.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + + +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from `environ'. */ +int +execvp (const char *file, char *const argv[]) +{ + return __execvpe (file, argv, __environ); +} +libc_hidden_def (execvp) diff --git a/REORG.TODO/posix/execvpe.c b/REORG.TODO/posix/execvpe.c new file mode 100644 index 0000000000..4d5be86a00 --- /dev/null +++ b/REORG.TODO/posix/execvpe.c @@ -0,0 +1,187 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <paths.h> +#include <confstr.h> +#include <sys/param.h> + +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif +#endif + +/* The file is accessible but it is not an executable file. Invoke + the shell to interpret it as a script. */ +static void +maybe_script_execute (const char *file, char *const argv[], char *const envp[]) +{ + ptrdiff_t argc; + for (argc = 0; argv[argc] != NULL; argc++) + { + if (argc == INT_MAX - 1) + { + errno = E2BIG; + return; + } + } + + /* Construct an argument list for the shell based on original arguments: + 1. Empty list (argv = { NULL }, argc = 1 }: new argv will contain 3 + arguments - default shell, script to execute, and ending NULL. + 2. Non empty argument list (argc = { ..., NULL }, argc > 1}: new argv + will contain also the default shell and the script to execute. It + will also skip the script name in arguments and only copy script + arguments. */ + char *new_argv[argc > 1 ? 2 + argc : 3]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) file; + if (argc > 1) + memcpy (new_argv + 2, argv + 1, argc * sizeof(char *)); + else + new_argv[2] = NULL; + + /* Execute the shell. */ + __execve (new_argv[0], new_argv, envp); +} + + +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from ENVP. */ +int +__execvpe (const char *file, char *const argv[], char *const envp[]) +{ + /* We check the simple case first. */ + if (*file == '\0') + { + __set_errno (ENOENT); + return -1; + } + + /* Don't search when it contains a slash. */ + if (strchr (file, '/') != NULL) + { + __execve (file, argv, envp); + + if (errno == ENOEXEC) + maybe_script_execute (file, argv, envp); + + return -1; + } + + const char *path = getenv ("PATH"); + if (!path) + path = CS_PATH; + /* Although GLIBC does not enforce NAME_MAX, we set it as the maximum + size to avoid unbounded stack allocation. Same applies for + PATH_MAX. */ + size_t file_len = __strnlen (file, NAME_MAX) + 1; + size_t path_len = __strnlen (path, PATH_MAX - 1) + 1; + + /* NAME_MAX does not include the terminating null character. */ + if ((file_len - 1 > NAME_MAX) + || !__libc_alloca_cutoff (path_len + file_len + 1)) + { + errno = ENAMETOOLONG; + return -1; + } + + const char *subp; + bool got_eacces = false; + /* The resulting string maximum size would be potentially a entry + in PATH plus '/' (path_len + 1) and then the the resulting file name + plus '\0' (file_len since it already accounts for the '\0'). */ + char buffer[path_len + file_len + 1]; + for (const char *p = path; ; p = subp) + { + subp = __strchrnul (p, ':'); + + /* PATH is larger than PATH_MAX and thus potentially larger than + the stack allocation. */ + if (subp - p >= path_len) + { + /* If there is only one path, bail out. */ + if (*subp == '\0') + break; + /* Otherwise skip to next one. */ + continue; + } + + /* Use the current path entry, plus a '/' if nonempty, plus the file to + execute. */ + char *pend = mempcpy (buffer, p, subp - p); + *pend = '/'; + memcpy (pend + (p < subp), file, file_len); + + __execve (buffer, argv, envp); + + if (errno == ENOEXEC) + /* This has O(P*C) behavior, where P is the length of the path and C + is the argument count. A better strategy would be allocate the + substitute argv and reuse it each time through the loop (so it + behaves as O(P+C) instead. */ + maybe_script_execute (buffer, argv, envp); + + switch (errno) + { + case EACCES: + /* Record that 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; + } + + if (*subp++ == '\0') + break; + } + + /* 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); + + return -1; +} + +weak_alias (__execvpe, execvpe) diff --git a/REORG.TODO/posix/fexecve.c b/REORG.TODO/posix/fexecve.c new file mode 100644 index 0000000000..5a57100722 --- /dev/null +++ b/REORG.TODO/posix/fexecve.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1994-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (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) diff --git a/REORG.TODO/posix/fnmatch.c b/REORG.TODO/posix/fnmatch.c new file mode 100644 index 0000000000..441a41f0a5 --- /dev/null +++ b/REORG.TODO/posix/fnmatch.c @@ -0,0 +1,465 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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> +#include <string.h> + +#if defined STDC_HEADERS || defined _LIBC +# include <stdlib.h> +#endif + +#ifdef _LIBC +# include <alloca.h> +#else +# define alloca_account(size., var) alloca (size) +#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 (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 (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 STRUCT fnmatch_struct +# 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) +# define WIDE_CHAR_VERSION 0 +# include <locale/weight.h> +# define FINDIDX findidx +# 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 STRUCT fnwmatch_struct +# 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 +/* Change the name the header defines so it doesn't conflict with + the <locale/weight.h> version included above. */ +# define findidx findidxwc +# include <locale/weightwc.h> +# undef findidx +# define FINDIDX findidxwc + +# 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 (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_malloc = NULL; + wchar_t *wpattern; + wchar_t *wstring_malloc = NULL; + wchar_t *wstring; + size_t alloca_used = 0; + + /* 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 (__glibc_likely (n < 1024)) + { + wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), + alloca_used); + n = mbsrtowcs (wpattern, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* 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)); + goto prepare_wpattern; + } + } + else + { + prepare_wpattern: + n = mbsrtowcs (NULL, &pattern, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + __set_errno (ENOMEM); + return -2; + } + wpattern_malloc = wpattern + = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + if (wpattern == NULL) + return -2; + (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); + } + + assert (mbsinit (&ps)); +#ifdef _LIBC + n = __strnlen (string, 1024); +#else + n = strlen (string); +#endif + p = string; + if (__glibc_likely (n < 1024)) + { + wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), + alloca_used); + n = mbsrtowcs (wstring, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + { + /* Something wrong. + XXX Do we have to set `errno' to something which + mbsrtows hasn't already done? */ + free_return: + free (wpattern_malloc); + return -1; + } + if (p) + { + memset (&ps, '\0', sizeof (ps)); + goto prepare_wstring; + } + } + else + { + prepare_wstring: + n = mbsrtowcs (NULL, &string, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + goto free_return; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + free (wpattern_malloc); + __set_errno (ENOMEM); + return -2; + } + + wstring_malloc = wstring + = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); + if (wstring == NULL) + { + free (wpattern_malloc); + return -2; + } + assert (mbsinit (&ps)); + (void) mbsrtowcs (wstring, &string, n + 1, &ps); + } + + int res = internal_fnwmatch (wpattern, wstring, wstring + n, + flags & FNM_PERIOD, flags, NULL, + alloca_used); + + free (wstring_malloc); + free (wpattern_malloc); + + return res; + } +# endif /* mbstate_t and mbsrtowcs or _LIBC. */ + + return internal_fnmatch (pattern, string, string + strlen (string), + flags & FNM_PERIOD, flags, NULL, 0); +} + +# 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/REORG.TODO/posix/fnmatch.h b/REORG.TODO/posix/fnmatch.h new file mode 100644 index 0000000000..71991617ab --- /dev/null +++ b/REORG.TODO/posix/fnmatch.h @@ -0,0 +1,62 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _FNMATCH_H +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#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/REORG.TODO/posix/fnmatch_loop.c b/REORG.TODO/posix/fnmatch_loop.c new file mode 100644 index 0000000000..2500dce615 --- /dev/null +++ b/REORG.TODO/posix/fnmatch_loop.c @@ -0,0 +1,1277 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> + +struct STRUCT +{ + const CHAR *pattern; + const CHAR *string; + int no_leading_period; +}; + +/* 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, + struct STRUCT *ends, size_t alloca_used) + internal_function; +static int EXT (INT opt, const CHAR *pattern, const CHAR *string, + const CHAR *string_end, int no_leading_period, int flags, + size_t alloca_used) + internal_function; +static const CHAR *END (const CHAR *patternp) internal_function; + +static int +internal_function +FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, + int no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used) +{ + const CHAR *p = pattern, *n = string; + 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 = EXT (c, p, n, string_end, no_leading_period, + flags, alloca_used); + 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 = EXT (c, p, n, string_end, no_leading_period, + flags, alloca_used); + if (res != -1) + return res; + } + else if (ends != NULL) + { + ends->pattern = p - 1; + ends->string = n; + ends->no_leading_period = no_leading_period; + return 0; + } + + 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; + struct STRUCT end; + + end.pattern = NULL; + 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)); + + for (--p; n < endp; ++n, no_leading_period = 0) + if (FCT (p, n, string_end, no_leading_period, flags2, + &end, alloca_used) == 0) + goto found; + } + 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, + NULL, alloca_used) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == L('\\') && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n, no_leading_period = 0) + if (FOLD ((UCHAR) *n) == c + && (FCT (p, n, string_end, no_leading_period, flags2, + &end, alloca_used) == 0)) + { + found: + if (end.pattern == NULL) + return 0; + break; + } + if (end.pattern != NULL) + { + p = end.pattern; + n = end.string; + no_leading_period = end.no_leading_period; + continue; + } + } + } + + /* 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. */ + const CHAR *p_init = p; + const CHAR *n_init = n; + 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('=')) + { + /* It's important that STR be a scalar variable rather + than a one-element array, because GCC (at least 4.9.2 + -O2 on x86-64) can be confused by the array and + diagnose a "used initialized" in a dead branch in the + findidx function. */ + UCHAR str; + 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 = 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) + goto matched; + } + else + { + const int32_t *table; +# if WIDE_CHAR_VERSION + const int32_t *weights; + const wint_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; + +# 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 wint_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 (table, indirect, extra, &cp, 1); + 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 & 0xffffff]; + int32_t idx2; + const UCHAR *np = (const UCHAR *) n; + + idx2 = FINDIDX (table, indirect, extra, + &np, string_end - n); + if (idx2 != 0 + && (idx >> 24) == (idx2 >> 24) + && len == weights[idx2 & 0xffffff]) + { + int cnt = 0; + + idx &= 0xffffff; + idx2 &= 0xffffff; + + 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, treat as normal character. */ + p = p_init; + n = n_init; + c = L('['); + goto normal_match; + } + 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; +# if 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; + +# if 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. */ +# if 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) + { +# if 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; +# if 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++; + +# if 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; +# if 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; + +# if 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. */ +# if 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; +# if 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 ( +# if 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 + { +# if 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; + } +# if 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. */ + while ((c = *p++) != L (']')) + { + 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 - 2; + break; + } + } + p += 2; + } + 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; + } + else if (c == L('[') && *p == L('.')) + { + while (1) + { + c = *++p; + if (c == L('\0')) + return FNM_NOMATCH; + + if (c == L('.') && p[1] == L(']')) + break; + } + p += 2; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + case L('+'): + case L('@'): + case L('!'): + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res = EXT (c, p, n, string_end, no_leading_period, flags, + alloca_used); + 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); + if (*p == L('\0')) + /* This is an invalid pattern. */ + return pattern; + } + 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, size_t alloca_used) +{ + const CHAR *startp; + int level; + struct patternlist + { + struct patternlist *next; + CHAR malloced; + CHAR str[0]; + } *list = NULL; + struct patternlist **lastp = &list; + size_t pattern_len = STRLEN (pattern); + int any_malloced = 0; + const CHAR *p; + const CHAR *rs; + int retval = 0; + + /* 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. */ + retval = -1; + goto out; + } + 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. */ + retval = -1; + goto out; + } + } + 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; \ + size_t slen = (opt == L('?') || opt == L('@') \ + ? pattern_len : (p - startp + 1)); \ + slen = sizeof (struct patternlist) + (slen * sizeof (CHAR)); \ + int malloced = ! __libc_use_alloca (alloca_used + slen); \ + if (__builtin_expect (malloced, 0)) \ + { \ + newp = malloc (slen); \ + if (newp == NULL) \ + { \ + retval = -2; \ + goto out; \ + } \ + any_malloced = 1; \ + } \ + else \ + newp = alloca_account (slen, alloca_used); \ + newp->next = NULL; \ + newp->malloced = malloced; \ + *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \ + *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, NULL, + alloca_used) == 0) + goto success; + /* 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, + NULL, alloca_used) == 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, NULL, alloca_used) == 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, NULL, + alloca_used) == 0))) + /* It worked. Signal success. */ + goto success; + } + while ((list = list->next) != NULL); + + /* None of the patterns lead to a match. */ + retval = FNM_NOMATCH; + break; + + case L('?'): + if (FCT (p, string, string_end, no_leading_period, flags, NULL, + alloca_used) == 0) + goto success; + /* 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, + NULL, alloca_used) == 0) + /* It worked. Signal success. */ + goto success; + while ((list = list->next) != NULL); + + /* None of the patterns lead to a match. */ + retval = FNM_NOMATCH; + break; + + 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, + NULL, alloca_used) == 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, + NULL, alloca_used) == 0)) + /* This is successful. */ + goto success; + } + + /* None of the patterns together with the rest of the pattern + lead to a match. */ + retval = FNM_NOMATCH; + break; + + default: + assert (! "Invalid extended matching operator"); + retval = -1; + break; + } + + success: + out: + if (any_malloced) + while (list != NULL) + { + struct patternlist *old = list; + list = list->next; + if (old->malloced) + free (old); + } + + return retval; +} + + +#undef FOLD +#undef CHAR +#undef UCHAR +#undef INT +#undef FCT +#undef EXT +#undef END +#undef STRUCT +#undef MEMPCPY +#undef MEMCHR +#undef STRCOLL +#undef STRLEN +#undef STRCAT +#undef L +#undef BTOWC +#undef WIDE_CHAR_VERSION +#undef FINDIDX diff --git a/REORG.TODO/posix/fork.c b/REORG.TODO/posix/fork.c new file mode 100644 index 0000000000..2b386b9529 --- /dev/null +++ b/REORG.TODO/posix/fork.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (void) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__fork) +stub_warning (fork) + +weak_alias (__fork, fork) diff --git a/REORG.TODO/posix/fpathconf.c b/REORG.TODO/posix/fpathconf.c new file mode 100644 index 0000000000..964521b29f --- /dev/null +++ b/REORG.TODO/posix/fpathconf.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Get file-specific information about descriptor FD. */ +long int +__fpathconf (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) diff --git a/REORG.TODO/posix/gai.conf b/REORG.TODO/posix/gai.conf new file mode 100644 index 0000000000..4616ed005b --- /dev/null +++ b/REORG.TODO/posix/gai.conf @@ -0,0 +1,65 @@ +# 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 +#label 2001:0::/32 7 +# +# 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. We also treat Teredo +# tunnels special. +# +# precedence <mask> <value> +# Add another rule to the 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 + +# +# scopev4 <mask> <value> +# Add another rule to the RFC 6724 scope table for IPv4 addresses. +# By default the scope IDs described in section 3.2 in RFC 6724 are +# used. Changing these defaults should hardly ever be necessary. +# The defaults are equivalent to: +# +#scopev4 ::ffff:169.254.0.0/112 2 +#scopev4 ::ffff:127.0.0.0/104 2 +#scopev4 ::ffff:0.0.0.0/96 14 diff --git a/REORG.TODO/posix/gai_strerror.c b/REORG.TODO/posix/gai_strerror.c new file mode 100644 index 0000000000..2fb422da83 --- /dev/null +++ b/REORG.TODO/posix/gai_strerror.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/get_child_max.c b/REORG.TODO/posix/get_child_max.c new file mode 100644 index 0000000000..1186121382 --- /dev/null +++ b/REORG.TODO/posix/get_child_max.c @@ -0,0 +1,28 @@ +/* Get POSIX {CHILD_MAX} run-time limit value. Stub version (no limit). + Copyright (C) 2006-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <limits.h> +#include <sys/sysinfo.h> + +#ifndef CHILD_MAX +long int +__get_child_max (void) +{ + return -1; +} +#endif diff --git a/REORG.TODO/posix/getaddrinfo.c b/REORG.TODO/posix/getaddrinfo.c new file mode 100644 index 0000000000..d03af5f65a --- /dev/null +++ b/REORG.TODO/posix/getaddrinfo.c @@ -0,0 +1,38 @@ +/* Stub version of getaddrinfo function. + Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/getconf-speclist.c b/REORG.TODO/posix/getconf-speclist.c new file mode 100644 index 0000000000..1415c88a39 --- /dev/null +++ b/REORG.TODO/posix/getconf-speclist.c @@ -0,0 +1,42 @@ +/* List POSIX compilation environments for this libc. + Copyright (C) 2012-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +#define START_ENV_GROUP(VERSION) \ + /* Empty. */ + +#define END_ENV_GROUP(VERSION) \ + /* Empty. */ + +#define KNOWN_ABSENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + /* Empty. */ + +#define KNOWN_PRESENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + @@@PRESENT_##ENV_PREFIX##_##SUFFIX + +#define UNKNOWN_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + /* Empty. */ + +#include "posix-envs.def" + +#undef START_ENV_GROUP +#undef END_ENV_GROUP +#undef KNOWN_ABSENT_ENVIRONMENT +#undef KNOWN_PRESENT_ENVIRONMENT +#undef UNKNOWN_ENVIRONMENT diff --git a/REORG.TODO/posix/getconf.c b/REORG.TODO/posix/getconf.c new file mode 100644 index 0000000000..01558481e2 --- /dev/null +++ b/REORG.TODO/posix/getconf.c @@ -0,0 +1,710 @@ +/* Copyright (C) 1991-2017 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 as published + by the Free Software Foundation; version 2 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#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 + +#define NEED_SPEC_ARRAY 1 +#include <posix-conf-vars.h> + +/* If all of the environments are defined in environments.h, then we don't need + to bother with doing a runtime check for a specific environment. */ +#if (defined _SC_V6_ILP32_OFF32 \ + && defined _SC_V7_LPBIG_OFFBIG \ + && defined _SC_XBS5_LP64_OFF64 \ + && defined _SC_V6_LP64_OFF64 \ + && defined _SC_V7_ILP32_OFFBIG \ + && defined _SC_V6_LPBIG_OFFBIG \ + && defined _SC_V7_LP64_OFF64 \ + && defined _SC_V7_ILP32_OFF32 \ + && defined _SC_XBS5_LPBIG_OFFBIG \ + && defined _SC_XBS5_ILP32_OFFBIG \ + && defined _SC_V6_ILP32_OFFBIG \ + && defined _SC_XBS5_ILP32_OFF32) +# define ALL_ENVIRONMENTS_DEFINED 1 +#endif + +struct conf + { + const char *name; + const int call_name; + const enum { SYSCONF, CONFSTR, PATHCONF } call; + }; + +static const struct conf vars[] = + { + { "LINK_MAX", _PC_LINK_MAX, PATHCONF }, + { "_POSIX_LINK_MAX", _PC_LINK_MAX, PATHCONF }, + { "MAX_CANON", _PC_MAX_CANON, PATHCONF }, + { "_POSIX_MAX_CANON", _PC_MAX_CANON, PATHCONF }, + { "MAX_INPUT", _PC_MAX_INPUT, PATHCONF }, + { "_POSIX_MAX_INPUT", _PC_MAX_INPUT, PATHCONF }, + { "NAME_MAX", _PC_NAME_MAX, PATHCONF }, + { "_POSIX_NAME_MAX", _PC_NAME_MAX, PATHCONF }, + { "PATH_MAX", _PC_PATH_MAX, PATHCONF }, + { "_POSIX_PATH_MAX", _PC_PATH_MAX, PATHCONF }, + { "PIPE_BUF", _PC_PIPE_BUF, PATHCONF }, + { "_POSIX_PIPE_BUF", _PC_PIPE_BUF, PATHCONF }, + { "SOCK_MAXBUF", _PC_SOCK_MAXBUF, PATHCONF }, + { "_POSIX_ASYNC_IO", _PC_ASYNC_IO, PATHCONF }, + { "_POSIX_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED, PATHCONF }, + { "_POSIX_NO_TRUNC", _PC_NO_TRUNC, PATHCONF }, + { "_POSIX_PRIO_IO", _PC_PRIO_IO, PATHCONF }, + { "_POSIX_SYNC_IO", _PC_SYNC_IO, PATHCONF }, + { "_POSIX_VDISABLE", _PC_VDISABLE, PATHCONF }, + + { "ARG_MAX", _SC_ARG_MAX, SYSCONF }, + { "ATEXIT_MAX", _SC_ATEXIT_MAX, SYSCONF }, + { "CHAR_BIT", _SC_CHAR_BIT, SYSCONF }, + { "CHAR_MAX", _SC_CHAR_MAX, SYSCONF }, + { "CHAR_MIN", _SC_CHAR_MIN, SYSCONF }, + { "CHILD_MAX", _SC_CHILD_MAX, SYSCONF }, + { "CLK_TCK", _SC_CLK_TCK, SYSCONF }, + { "INT_MAX", _SC_INT_MAX, SYSCONF }, + { "INT_MIN", _SC_INT_MIN, SYSCONF }, + { "IOV_MAX", _SC_UIO_MAXIOV, SYSCONF }, + { "LOGNAME_MAX", _SC_LOGIN_NAME_MAX, SYSCONF }, + { "LONG_BIT", _SC_LONG_BIT, SYSCONF }, + { "MB_LEN_MAX", _SC_MB_LEN_MAX, SYSCONF }, + { "NGROUPS_MAX", _SC_NGROUPS_MAX, SYSCONF }, + { "NL_ARGMAX", _SC_NL_ARGMAX, SYSCONF }, + { "NL_LANGMAX", _SC_NL_LANGMAX, SYSCONF }, + { "NL_MSGMAX", _SC_NL_MSGMAX, SYSCONF }, + { "NL_NMAX", _SC_NL_NMAX, SYSCONF }, + { "NL_SETMAX", _SC_NL_SETMAX, SYSCONF }, + { "NL_TEXTMAX", _SC_NL_TEXTMAX, SYSCONF }, + { "NSS_BUFLEN_GROUP", _SC_GETGR_R_SIZE_MAX, SYSCONF }, + { "NSS_BUFLEN_PASSWD", _SC_GETPW_R_SIZE_MAX, SYSCONF }, + { "NZERO", _SC_NZERO, SYSCONF }, + { "OPEN_MAX", _SC_OPEN_MAX, SYSCONF }, + { "PAGESIZE", _SC_PAGESIZE, SYSCONF }, + { "PAGE_SIZE", _SC_PAGESIZE, SYSCONF }, + { "PASS_MAX", _SC_PASS_MAX, SYSCONF }, + { "PTHREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS, SYSCONF }, + { "PTHREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX, SYSCONF }, + { "PTHREAD_STACK_MIN", _SC_THREAD_STACK_MIN, SYSCONF }, + { "PTHREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX, SYSCONF }, + { "SCHAR_MAX", _SC_SCHAR_MAX, SYSCONF }, + { "SCHAR_MIN", _SC_SCHAR_MIN, SYSCONF }, + { "SHRT_MAX", _SC_SHRT_MAX, SYSCONF }, + { "SHRT_MIN", _SC_SHRT_MIN, SYSCONF }, + { "SSIZE_MAX", _SC_SSIZE_MAX, SYSCONF }, + { "TTY_NAME_MAX", _SC_TTY_NAME_MAX, SYSCONF }, + { "TZNAME_MAX", _SC_TZNAME_MAX, SYSCONF }, + { "UCHAR_MAX", _SC_UCHAR_MAX, SYSCONF }, + { "UINT_MAX", _SC_UINT_MAX, SYSCONF }, + { "UIO_MAXIOV", _SC_UIO_MAXIOV, SYSCONF }, + { "ULONG_MAX", _SC_ULONG_MAX, SYSCONF }, + { "USHRT_MAX", _SC_USHRT_MAX, SYSCONF }, + { "WORD_BIT", _SC_WORD_BIT, SYSCONF }, + { "_AVPHYS_PAGES", _SC_AVPHYS_PAGES, SYSCONF }, + { "_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF, SYSCONF }, + { "_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN, SYSCONF }, + { "_PHYS_PAGES", _SC_PHYS_PAGES, SYSCONF }, + { "_POSIX_ARG_MAX", _SC_ARG_MAX, SYSCONF }, + { "_POSIX_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO, SYSCONF }, + { "_POSIX_CHILD_MAX", _SC_CHILD_MAX, SYSCONF }, + { "_POSIX_FSYNC", _SC_FSYNC, SYSCONF }, + { "_POSIX_JOB_CONTROL", _SC_JOB_CONTROL, SYSCONF }, + { "_POSIX_MAPPED_FILES", _SC_MAPPED_FILES, SYSCONF }, + { "_POSIX_MEMLOCK", _SC_MEMLOCK, SYSCONF }, + { "_POSIX_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE, SYSCONF }, + { "_POSIX_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION, SYSCONF }, + { "_POSIX_MESSAGE_PASSING", _SC_MESSAGE_PASSING, SYSCONF }, + { "_POSIX_NGROUPS_MAX", _SC_NGROUPS_MAX, SYSCONF }, + { "_POSIX_OPEN_MAX", _SC_OPEN_MAX, SYSCONF }, + { "_POSIX_PII", _SC_PII, SYSCONF }, + { "_POSIX_PII_INTERNET", _SC_PII_INTERNET, SYSCONF }, + { "_POSIX_PII_INTERNET_DGRAM", _SC_PII_INTERNET_DGRAM, SYSCONF }, + { "_POSIX_PII_INTERNET_STREAM", _SC_PII_INTERNET_STREAM, SYSCONF }, + { "_POSIX_PII_OSI", _SC_PII_OSI, SYSCONF }, + { "_POSIX_PII_OSI_CLTS", _SC_PII_OSI_CLTS, SYSCONF }, + { "_POSIX_PII_OSI_COTS", _SC_PII_OSI_COTS, SYSCONF }, + { "_POSIX_PII_OSI_M", _SC_PII_OSI_M, SYSCONF }, + { "_POSIX_PII_SOCKET", _SC_PII_SOCKET, SYSCONF }, + { "_POSIX_PII_XTI", _SC_PII_XTI, SYSCONF }, + { "_POSIX_POLL", _SC_POLL, SYSCONF }, + { "_POSIX_PRIORITIZED_IO", _SC_PRIORITIZED_IO, SYSCONF }, + { "_POSIX_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING, SYSCONF }, + { "_POSIX_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS, SYSCONF }, + { "_POSIX_SAVED_IDS", _SC_SAVED_IDS, SYSCONF }, + { "_POSIX_SELECT", _SC_SELECT, SYSCONF }, + { "_POSIX_SEMAPHORES", _SC_SEMAPHORES, SYSCONF }, + { "_POSIX_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS, SYSCONF }, + { "_POSIX_SSIZE_MAX", _SC_SSIZE_MAX, SYSCONF }, + { "_POSIX_STREAM_MAX", _SC_STREAM_MAX, SYSCONF }, + { "_POSIX_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO, SYSCONF }, + { "_POSIX_THREADS", _SC_THREADS, SYSCONF }, + { "_POSIX_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR, SYSCONF }, + { "_POSIX_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE, SYSCONF }, + { "_POSIX_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING, SYSCONF }, + { "_POSIX_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT, SYSCONF }, + { "_POSIX_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT, SYSCONF }, + { "_POSIX_THREAD_ROBUST_PRIO_INHERIT", _SC_THREAD_ROBUST_PRIO_INHERIT, + SYSCONF }, + { "_POSIX_THREAD_ROBUST_PRIO_PROTECT", _SC_THREAD_ROBUST_PRIO_PROTECT, + SYSCONF }, + { "_POSIX_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED, SYSCONF }, + { "_POSIX_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS, SYSCONF }, + { "_POSIX_TIMERS", _SC_TIMERS, SYSCONF }, + { "TIMER_MAX", _SC_TIMER_MAX, SYSCONF }, + { "_POSIX_TZNAME_MAX", _SC_TZNAME_MAX, SYSCONF }, + { "_POSIX_VERSION", _SC_VERSION, SYSCONF }, + { "_T_IOV_MAX", _SC_T_IOV_MAX, SYSCONF }, + { "_XOPEN_CRYPT", _SC_XOPEN_CRYPT, SYSCONF }, + { "_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N, SYSCONF }, + { "_XOPEN_LEGACY", _SC_XOPEN_LEGACY, SYSCONF }, + { "_XOPEN_REALTIME", _SC_XOPEN_REALTIME, SYSCONF }, + { "_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS, SYSCONF }, + { "_XOPEN_SHM", _SC_XOPEN_SHM, SYSCONF }, + { "_XOPEN_UNIX", _SC_XOPEN_UNIX, SYSCONF }, + { "_XOPEN_VERSION", _SC_XOPEN_VERSION, SYSCONF }, + { "_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION, SYSCONF }, + { "_XOPEN_XPG2", _SC_XOPEN_XPG2, SYSCONF }, + { "_XOPEN_XPG3", _SC_XOPEN_XPG3, SYSCONF }, + { "_XOPEN_XPG4", _SC_XOPEN_XPG4, SYSCONF }, + /* POSIX.2 */ + { "BC_BASE_MAX", _SC_BC_BASE_MAX, SYSCONF }, + { "BC_DIM_MAX", _SC_BC_DIM_MAX, SYSCONF }, + { "BC_SCALE_MAX", _SC_BC_SCALE_MAX, SYSCONF }, + { "BC_STRING_MAX", _SC_BC_STRING_MAX, SYSCONF }, + { "CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX, SYSCONF }, + { "COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX, SYSCONF }, + { "EQUIV_CLASS_MAX", _SC_EQUIV_CLASS_MAX, SYSCONF }, + { "EXPR_NEST_MAX", _SC_EXPR_NEST_MAX, SYSCONF }, + { "LINE_MAX", _SC_LINE_MAX, SYSCONF }, + { "POSIX2_BC_BASE_MAX", _SC_BC_BASE_MAX, SYSCONF }, + { "POSIX2_BC_DIM_MAX", _SC_BC_DIM_MAX, SYSCONF }, + { "POSIX2_BC_SCALE_MAX", _SC_BC_SCALE_MAX, SYSCONF }, + { "POSIX2_BC_STRING_MAX", _SC_BC_STRING_MAX, SYSCONF }, + { "POSIX2_CHAR_TERM", _SC_2_CHAR_TERM, SYSCONF }, + { "POSIX2_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX, SYSCONF }, + { "POSIX2_C_BIND", _SC_2_C_BIND, SYSCONF }, + { "POSIX2_C_DEV", _SC_2_C_DEV, SYSCONF }, + { "POSIX2_C_VERSION", _SC_2_C_VERSION, SYSCONF }, + { "POSIX2_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX, SYSCONF }, + { "POSIX2_FORT_DEV", _SC_2_FORT_DEV, SYSCONF }, + { "POSIX2_FORT_RUN", _SC_2_FORT_RUN, SYSCONF }, + { "_POSIX2_LINE_MAX", _SC_LINE_MAX, SYSCONF }, + { "POSIX2_LINE_MAX", _SC_LINE_MAX, SYSCONF }, + { "POSIX2_LOCALEDEF", _SC_2_LOCALEDEF, SYSCONF }, + { "POSIX2_RE_DUP_MAX", _SC_RE_DUP_MAX, SYSCONF }, + { "POSIX2_SW_DEV", _SC_2_SW_DEV, SYSCONF }, + { "POSIX2_UPE", _SC_2_UPE, SYSCONF }, + { "POSIX2_VERSION", _SC_2_VERSION, SYSCONF }, + { "RE_DUP_MAX", _SC_RE_DUP_MAX, SYSCONF }, + + { "PATH", _CS_PATH, CONFSTR }, + { "CS_PATH", _CS_PATH, CONFSTR }, + + /* LFS */ + { "LFS_CFLAGS", _CS_LFS_CFLAGS, CONFSTR }, + { "LFS_LDFLAGS", _CS_LFS_LDFLAGS, CONFSTR }, + { "LFS_LIBS", _CS_LFS_LIBS, CONFSTR }, + { "LFS_LINTFLAGS", _CS_LFS_LINTFLAGS, CONFSTR }, + { "LFS64_CFLAGS", _CS_LFS64_CFLAGS, CONFSTR }, + { "LFS64_LDFLAGS", _CS_LFS64_LDFLAGS, CONFSTR }, + { "LFS64_LIBS", _CS_LFS64_LIBS, CONFSTR }, + { "LFS64_LINTFLAGS", _CS_LFS64_LINTFLAGS, CONFSTR }, + + /* Programming environments. */ + { "_XBS5_WIDTH_RESTRICTED_ENVS", _CS_V5_WIDTH_RESTRICTED_ENVS, CONFSTR }, + { "XBS5_WIDTH_RESTRICTED_ENVS", _CS_V5_WIDTH_RESTRICTED_ENVS, CONFSTR }, + + { "_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32, SYSCONF }, + { "XBS5_ILP32_OFF32_CFLAGS", _CS_XBS5_ILP32_OFF32_CFLAGS, CONFSTR }, + { "XBS5_ILP32_OFF32_LDFLAGS", _CS_XBS5_ILP32_OFF32_LDFLAGS, CONFSTR }, + { "XBS5_ILP32_OFF32_LIBS", _CS_XBS5_ILP32_OFF32_LIBS, CONFSTR }, + { "XBS5_ILP32_OFF32_LINTFLAGS", _CS_XBS5_ILP32_OFF32_LINTFLAGS, CONFSTR }, + + { "_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG, SYSCONF }, + { "XBS5_ILP32_OFFBIG_CFLAGS", _CS_XBS5_ILP32_OFFBIG_CFLAGS, CONFSTR }, + { "XBS5_ILP32_OFFBIG_LDFLAGS", _CS_XBS5_ILP32_OFFBIG_LDFLAGS, CONFSTR }, + { "XBS5_ILP32_OFFBIG_LIBS", _CS_XBS5_ILP32_OFFBIG_LIBS, CONFSTR }, + { "XBS5_ILP32_OFFBIG_LINTFLAGS", _CS_XBS5_ILP32_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64, SYSCONF }, + { "XBS5_LP64_OFF64_CFLAGS", _CS_XBS5_LP64_OFF64_CFLAGS, CONFSTR }, + { "XBS5_LP64_OFF64_LDFLAGS", _CS_XBS5_LP64_OFF64_LDFLAGS, CONFSTR }, + { "XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS, CONFSTR }, + { "XBS5_LP64_OFF64_LINTFLAGS", _CS_XBS5_LP64_OFF64_LINTFLAGS, CONFSTR }, + + { "_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG, SYSCONF }, + { "XBS5_LPBIG_OFFBIG_CFLAGS", _CS_XBS5_LPBIG_OFFBIG_CFLAGS, CONFSTR }, + { "XBS5_LPBIG_OFFBIG_LDFLAGS", _CS_XBS5_LPBIG_OFFBIG_LDFLAGS, CONFSTR }, + { "XBS5_LPBIG_OFFBIG_LIBS", _CS_XBS5_LPBIG_OFFBIG_LIBS, CONFSTR }, + { "XBS5_LPBIG_OFFBIG_LINTFLAGS", _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_POSIX_V6_ILP32_OFF32", _SC_V6_ILP32_OFF32, SYSCONF }, + { "POSIX_V6_ILP32_OFF32_CFLAGS", _CS_POSIX_V6_ILP32_OFF32_CFLAGS, CONFSTR }, + { "POSIX_V6_ILP32_OFF32_LDFLAGS", _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, CONFSTR }, + { "POSIX_V6_ILP32_OFF32_LIBS", _CS_POSIX_V6_ILP32_OFF32_LIBS, CONFSTR }, + { "POSIX_V6_ILP32_OFF32_LINTFLAGS", _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS, CONFSTR }, + + { "_POSIX_V6_WIDTH_RESTRICTED_ENVS", _CS_V6_WIDTH_RESTRICTED_ENVS, CONFSTR }, + { "POSIX_V6_WIDTH_RESTRICTED_ENVS", _CS_V6_WIDTH_RESTRICTED_ENVS, CONFSTR }, + + { "_POSIX_V6_ILP32_OFFBIG", _SC_V6_ILP32_OFFBIG, SYSCONF }, + { "POSIX_V6_ILP32_OFFBIG_CFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, CONFSTR }, + { "POSIX_V6_ILP32_OFFBIG_LDFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, CONFSTR }, + { "POSIX_V6_ILP32_OFFBIG_LIBS", _CS_POSIX_V6_ILP32_OFFBIG_LIBS, CONFSTR }, + { "POSIX_V6_ILP32_OFFBIG_LINTFLAGS", _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_POSIX_V6_LP64_OFF64", _SC_V6_LP64_OFF64, SYSCONF }, + { "POSIX_V6_LP64_OFF64_CFLAGS", _CS_POSIX_V6_LP64_OFF64_CFLAGS, CONFSTR }, + { "POSIX_V6_LP64_OFF64_LDFLAGS", _CS_POSIX_V6_LP64_OFF64_LDFLAGS, CONFSTR }, + { "POSIX_V6_LP64_OFF64_LIBS", _CS_POSIX_V6_LP64_OFF64_LIBS, CONFSTR }, + { "POSIX_V6_LP64_OFF64_LINTFLAGS", _CS_POSIX_V6_LP64_OFF64_LINTFLAGS, CONFSTR }, + + { "_POSIX_V6_LPBIG_OFFBIG", _SC_V6_LPBIG_OFFBIG, SYSCONF }, + { "POSIX_V6_LPBIG_OFFBIG_CFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, CONFSTR }, + { "POSIX_V6_LPBIG_OFFBIG_LDFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, CONFSTR }, + { "POSIX_V6_LPBIG_OFFBIG_LIBS", _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, CONFSTR }, + { "POSIX_V6_LPBIG_OFFBIG_LINTFLAGS", _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_POSIX_V7_ILP32_OFF32", _SC_V7_ILP32_OFF32, SYSCONF }, + { "POSIX_V7_ILP32_OFF32_CFLAGS", _CS_POSIX_V7_ILP32_OFF32_CFLAGS, CONFSTR }, + { "POSIX_V7_ILP32_OFF32_LDFLAGS", _CS_POSIX_V7_ILP32_OFF32_LDFLAGS, CONFSTR }, + { "POSIX_V7_ILP32_OFF32_LIBS", _CS_POSIX_V7_ILP32_OFF32_LIBS, CONFSTR }, + { "POSIX_V7_ILP32_OFF32_LINTFLAGS", _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS, CONFSTR }, + + { "_POSIX_V7_WIDTH_RESTRICTED_ENVS", _CS_V7_WIDTH_RESTRICTED_ENVS, CONFSTR }, + { "POSIX_V7_WIDTH_RESTRICTED_ENVS", _CS_V7_WIDTH_RESTRICTED_ENVS, CONFSTR }, + + { "_POSIX_V7_ILP32_OFFBIG", _SC_V7_ILP32_OFFBIG, SYSCONF }, + { "POSIX_V7_ILP32_OFFBIG_CFLAGS", _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS, CONFSTR }, + { "POSIX_V7_ILP32_OFFBIG_LDFLAGS", _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS, CONFSTR }, + { "POSIX_V7_ILP32_OFFBIG_LIBS", _CS_POSIX_V7_ILP32_OFFBIG_LIBS, CONFSTR }, + { "POSIX_V7_ILP32_OFFBIG_LINTFLAGS", _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_POSIX_V7_LP64_OFF64", _SC_V7_LP64_OFF64, SYSCONF }, + { "POSIX_V7_LP64_OFF64_CFLAGS", _CS_POSIX_V7_LP64_OFF64_CFLAGS, CONFSTR }, + { "POSIX_V7_LP64_OFF64_LDFLAGS", _CS_POSIX_V7_LP64_OFF64_LDFLAGS, CONFSTR }, + { "POSIX_V7_LP64_OFF64_LIBS", _CS_POSIX_V7_LP64_OFF64_LIBS, CONFSTR }, + { "POSIX_V7_LP64_OFF64_LINTFLAGS", _CS_POSIX_V7_LP64_OFF64_LINTFLAGS, CONFSTR }, + + { "_POSIX_V7_LPBIG_OFFBIG", _SC_V7_LPBIG_OFFBIG, SYSCONF }, + { "POSIX_V7_LPBIG_OFFBIG_CFLAGS", _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS, CONFSTR }, + { "POSIX_V7_LPBIG_OFFBIG_LDFLAGS", _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS, CONFSTR }, + { "POSIX_V7_LPBIG_OFFBIG_LIBS", _CS_POSIX_V7_LPBIG_OFFBIG_LIBS, CONFSTR }, + { "POSIX_V7_LPBIG_OFFBIG_LINTFLAGS", _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS, CONFSTR }, + + { "_POSIX_ADVISORY_INFO", _SC_ADVISORY_INFO, SYSCONF }, + { "_POSIX_BARRIERS", _SC_BARRIERS, SYSCONF }, + { "_POSIX_BASE", _SC_BASE, SYSCONF }, + { "_POSIX_C_LANG_SUPPORT", _SC_C_LANG_SUPPORT, SYSCONF }, + { "_POSIX_C_LANG_SUPPORT_R", _SC_C_LANG_SUPPORT_R, SYSCONF }, + { "_POSIX_CLOCK_SELECTION", _SC_CLOCK_SELECTION, SYSCONF }, + { "_POSIX_CPUTIME", _SC_CPUTIME, SYSCONF }, + { "_POSIX_THREAD_CPUTIME", _SC_THREAD_CPUTIME, SYSCONF }, + { "_POSIX_DEVICE_SPECIFIC", _SC_DEVICE_SPECIFIC, SYSCONF }, + { "_POSIX_DEVICE_SPECIFIC_R", _SC_DEVICE_SPECIFIC_R, SYSCONF }, + { "_POSIX_FD_MGMT", _SC_FD_MGMT, SYSCONF }, + { "_POSIX_FIFO", _SC_FIFO, SYSCONF }, + { "_POSIX_PIPE", _SC_PIPE, SYSCONF }, + { "_POSIX_FILE_ATTRIBUTES", _SC_FILE_ATTRIBUTES, SYSCONF }, + { "_POSIX_FILE_LOCKING", _SC_FILE_LOCKING, SYSCONF }, + { "_POSIX_FILE_SYSTEM", _SC_FILE_SYSTEM, SYSCONF }, + { "_POSIX_MONOTONIC_CLOCK", _SC_MONOTONIC_CLOCK, SYSCONF }, + { "_POSIX_MULTI_PROCESS", _SC_MULTI_PROCESS, SYSCONF }, + { "_POSIX_SINGLE_PROCESS", _SC_SINGLE_PROCESS, SYSCONF }, + { "_POSIX_NETWORKING", _SC_NETWORKING, SYSCONF }, + { "_POSIX_READER_WRITER_LOCKS", _SC_READER_WRITER_LOCKS, SYSCONF }, + { "_POSIX_SPIN_LOCKS", _SC_SPIN_LOCKS, SYSCONF }, + { "_POSIX_REGEXP", _SC_REGEXP, SYSCONF }, + { "_REGEX_VERSION", _SC_REGEX_VERSION, SYSCONF }, + { "_POSIX_SHELL", _SC_SHELL, SYSCONF }, + { "_POSIX_SIGNALS", _SC_SIGNALS, SYSCONF }, + { "_POSIX_SPAWN", _SC_SPAWN, SYSCONF }, + { "_POSIX_SPORADIC_SERVER", _SC_SPORADIC_SERVER, SYSCONF }, + { "_POSIX_THREAD_SPORADIC_SERVER", _SC_THREAD_SPORADIC_SERVER, SYSCONF }, + { "_POSIX_SYSTEM_DATABASE", _SC_SYSTEM_DATABASE, SYSCONF }, + { "_POSIX_SYSTEM_DATABASE_R", _SC_SYSTEM_DATABASE_R, SYSCONF }, + { "_POSIX_TIMEOUTS", _SC_TIMEOUTS, SYSCONF }, + { "_POSIX_TYPED_MEMORY_OBJECTS", _SC_TYPED_MEMORY_OBJECTS, SYSCONF }, + { "_POSIX_USER_GROUPS", _SC_USER_GROUPS, SYSCONF }, + { "_POSIX_USER_GROUPS_R", _SC_USER_GROUPS_R, SYSCONF }, + { "POSIX2_PBS", _SC_2_PBS, SYSCONF }, + { "POSIX2_PBS_ACCOUNTING", _SC_2_PBS_ACCOUNTING, SYSCONF }, + { "POSIX2_PBS_LOCATE", _SC_2_PBS_LOCATE, SYSCONF }, + { "POSIX2_PBS_TRACK", _SC_2_PBS_TRACK, SYSCONF }, + { "POSIX2_PBS_MESSAGE", _SC_2_PBS_MESSAGE, SYSCONF }, + { "SYMLOOP_MAX", _SC_SYMLOOP_MAX, SYSCONF }, + { "STREAM_MAX", _SC_STREAM_MAX, SYSCONF }, + { "AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX, SYSCONF }, + { "AIO_MAX", _SC_AIO_MAX, SYSCONF }, + { "AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX, SYSCONF }, + { "DELAYTIMER_MAX", _SC_DELAYTIMER_MAX, SYSCONF }, + { "HOST_NAME_MAX", _SC_HOST_NAME_MAX, SYSCONF }, + { "LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX, SYSCONF }, + { "MQ_OPEN_MAX", _SC_MQ_OPEN_MAX, SYSCONF }, + { "MQ_PRIO_MAX", _SC_MQ_PRIO_MAX, SYSCONF }, + { "_POSIX_DEVICE_IO", _SC_DEVICE_IO, SYSCONF }, + { "_POSIX_TRACE", _SC_TRACE, SYSCONF }, + { "_POSIX_TRACE_EVENT_FILTER", _SC_TRACE_EVENT_FILTER, SYSCONF }, + { "_POSIX_TRACE_INHERIT", _SC_TRACE_INHERIT, SYSCONF }, + { "_POSIX_TRACE_LOG", _SC_TRACE_LOG, SYSCONF }, + { "RTSIG_MAX", _SC_RTSIG_MAX, SYSCONF }, + { "SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX, SYSCONF }, + { "SEM_VALUE_MAX", _SC_SEM_VALUE_MAX, SYSCONF }, + { "SIGQUEUE_MAX", _SC_SIGQUEUE_MAX, SYSCONF }, + { "FILESIZEBITS", _PC_FILESIZEBITS, PATHCONF }, + { "POSIX_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN, PATHCONF }, + { "POSIX_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE, PATHCONF }, + { "POSIX_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE, PATHCONF }, + { "POSIX_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE, PATHCONF }, + { "POSIX_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN, PATHCONF }, + { "SYMLINK_MAX", _PC_SYMLINK_MAX, PATHCONF }, + { "GNU_LIBC_VERSION", _CS_GNU_LIBC_VERSION, CONFSTR }, + { "GNU_LIBPTHREAD_VERSION", _CS_GNU_LIBPTHREAD_VERSION, CONFSTR }, + { "POSIX2_SYMLINKS", _PC_2_SYMLINKS, PATHCONF }, + + { "LEVEL1_ICACHE_SIZE", _SC_LEVEL1_ICACHE_SIZE, SYSCONF }, + { "LEVEL1_ICACHE_ASSOC", _SC_LEVEL1_ICACHE_ASSOC, SYSCONF }, + { "LEVEL1_ICACHE_LINESIZE", _SC_LEVEL1_ICACHE_LINESIZE, SYSCONF }, + { "LEVEL1_DCACHE_SIZE", _SC_LEVEL1_DCACHE_SIZE, SYSCONF }, + { "LEVEL1_DCACHE_ASSOC", _SC_LEVEL1_DCACHE_ASSOC, SYSCONF }, + { "LEVEL1_DCACHE_LINESIZE", _SC_LEVEL1_DCACHE_LINESIZE, SYSCONF }, + { "LEVEL2_CACHE_SIZE", _SC_LEVEL2_CACHE_SIZE, SYSCONF }, + { "LEVEL2_CACHE_ASSOC", _SC_LEVEL2_CACHE_ASSOC, SYSCONF }, + { "LEVEL2_CACHE_LINESIZE", _SC_LEVEL2_CACHE_LINESIZE, SYSCONF }, + { "LEVEL3_CACHE_SIZE", _SC_LEVEL3_CACHE_SIZE, SYSCONF }, + { "LEVEL3_CACHE_ASSOC", _SC_LEVEL3_CACHE_ASSOC, SYSCONF }, + { "LEVEL3_CACHE_LINESIZE", _SC_LEVEL3_CACHE_LINESIZE, SYSCONF }, + { "LEVEL4_CACHE_SIZE", _SC_LEVEL4_CACHE_SIZE, SYSCONF }, + { "LEVEL4_CACHE_ASSOC", _SC_LEVEL4_CACHE_ASSOC, SYSCONF }, + { "LEVEL4_CACHE_LINESIZE", _SC_LEVEL4_CACHE_LINESIZE, SYSCONF }, + + { "IPV6", _SC_IPV6, SYSCONF }, + { "RAW_SOCKETS", _SC_RAW_SOCKETS, SYSCONF }, + + { "_POSIX_IPV6", _SC_IPV6, SYSCONF }, + { "_POSIX_RAW_SOCKETS", _SC_RAW_SOCKETS, SYSCONF }, + + { NULL, 0, SYSCONF } + }; + + +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) +{ + 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[]) +{ + 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) + { + printf ("getconf %s%s\n", PKGVERSION, VERSION); + printf (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\ +"), "2017"); + printf (gettext ("Written by %s.\n"), "Roland McGrath"); + return 0; + } + + if (argc > 1 && strcmp (argv[1], "--help") == 0) + { + printf (gettext ("\ +Usage: getconf [-v SPEC] VAR\n\ + or: getconf [-v SPEC] PATH_VAR PATH\n\ +\n\ +Get the configuration value for variable VAR, or for variable PATH_VAR\n\ +for path PATH. If SPEC is given, give values for compilation\n\ +environment SPEC.\n\n")); + printf (gettext ("For bug reporting instructions, please see:\n\ +%s.\n"), REPORT_BUGS_TO); + return 0; + } + +#ifdef ALL_ENVIRONMENTS_DEFINED + if (argc > 1 && strncmp (argv[1], "-v", 2) == 0) + { + if (argv[1][2] == '\0') + { + if (argc < 3) + usage (); + + argv += 2; + argc -= 2; + } + else + { + argv += 1; + argc += 1; + } + } +#else + 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) + { + size_t 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 _XBS5_ILP32_OFF32 + case _SC_XBS5_ILP32_OFF32: +# endif +# ifndef _XBS5_ILP32_OFFBIG + case _SC_XBS5_ILP32_OFFBIG: +# endif +# ifndef _XBS5_LP64_OFF64 + case _SC_XBS5_LP64_OFF64: +# endif +# ifndef _XBS5_LPBIG_OFFBIG + case _SC_XBS5_LPBIG_OFFBIG: +# endif +# 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 +# ifndef _POSIX_V7_ILP32_OFF32 + case _SC_V7_ILP32_OFF32: +# endif +# ifndef _POSIX_V7_ILP32_OFFBIG + case _SC_V7_ILP32_OFFBIG: +# endif +# ifndef _POSIX_V7_LP64_OFF64 + case _SC_V7_LP64_OFF64: +# endif +# ifndef _POSIX_V7_LPBIG_OFFBIG + case _SC_V7_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; + } + } +#endif + + if (argc > 1 && strcmp (argv[1], "-a") == 0) + { + if (argc == 2) + print_all ("/"); + else if (argc == 3) + print_all (argv[2]); + else + usage (); + } + + int ai = 1; + if (argc > ai && strcmp (argv[ai], "--") == 0) + ++ai; + + if (argc - ai < 1 || argc - ai > 2) + usage (); + + for (c = vars; c->name != NULL; ++c) + if (strcmp (c->name, argv[ai]) == 0 + || (strncmp (c->name, "_POSIX_", 7) == 0 + && strcmp (c->name + 7, argv[ai]) == 0)) + { + long int value; + size_t clen; + char *cvalue; + switch (c->call) + { + case PATHCONF: + if (argc - ai < 2) + usage (); + errno = 0; + value = pathconf (argv[ai + 1], c->call_name); + if (value == -1) + { + if (errno) + error (3, errno, "pathconf: %s", argv[ai + 1]); + else + puts (_("undefined")); + } + else + printf ("%ld\n", value); + exit (0); + + case SYSCONF: + if (argc - ai > 1) + 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 - ai > 1) + 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[ai]); + /* NOTREACHED */ + return 2; +} diff --git a/REORG.TODO/posix/getegid.c b/REORG.TODO/posix/getegid.c new file mode 100644 index 0000000000..b278a30c7f --- /dev/null +++ b/REORG.TODO/posix/getegid.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Get the effective group ID of the calling process. */ +__gid_t +__getegid (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getegid) + +weak_alias (__getegid, getegid) diff --git a/REORG.TODO/posix/geteuid.c b/REORG.TODO/posix/geteuid.c new file mode 100644 index 0000000000..b77d2b8882 --- /dev/null +++ b/REORG.TODO/posix/geteuid.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + + +/* Get the effective user ID of the calling process. */ +__uid_t +__geteuid (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (geteuid) + +weak_alias (__geteuid, geteuid) diff --git a/REORG.TODO/posix/getgid.c b/REORG.TODO/posix/getgid.c new file mode 100644 index 0000000000..b0330ebef4 --- /dev/null +++ b/REORG.TODO/posix/getgid.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Get the real group ID of the calling process. */ +gid_t +__getgid (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getgid) + +weak_alias (__getgid, getgid) diff --git a/REORG.TODO/posix/getgroups.c b/REORG.TODO/posix/getgroups.c new file mode 100644 index 0000000000..960618b557 --- /dev/null +++ b/REORG.TODO/posix/getgroups.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (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) diff --git a/REORG.TODO/posix/getopt.c b/REORG.TODO/posix/getopt.c new file mode 100644 index 0000000000..543c8e7284 --- /dev/null +++ b/REORG.TODO/posix/getopt.c @@ -0,0 +1,810 @@ +/* Getopt for GNU. + Copyright (C) 1987-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBC +# include <config.h> +#endif + +#include "getopt.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef _LIBC +/* When used as part of glibc, error printing must be done differently + for standards compliance. getopt is not a cancellation point, so + it must not call functions that are, and it is specified by an + older standard than stdio locking, so it must not refer to + functions in the "user namespace" related to stdio locking. + Finally, it must use glibc's internal message translation so that + the messages are looked up in the proper text domain. */ +# include <libintl.h> +# define fprintf __fxprintf_nocancel +# define flockfile(fp) _IO_flockfile (fp) +# define funlockfile(fp) _IO_funlockfile (fp) +#else +# include "gettext.h" +# define _(msgid) gettext (msgid) +/* When used standalone, flockfile and funlockfile might not be + available. */ +# ifndef _POSIX_THREAD_SAFE_FUNCTIONS +# define flockfile(fp) /* nop */ +# define funlockfile(fp) /* nop */ +# endif +/* When used standalone, do not attempt to use alloca. */ +# define __libc_use_alloca(size) 0 +# undef alloca +# define alloca(size) (abort (), (void *)0) +#endif + +/* This implementation of 'getopt' has three modes for handling + options interspersed with non-option arguments. It can stop + scanning for options at the first non-option argument encountered, + as POSIX specifies. It can continue scanning for options after the + first non-option argument, but permute 'argv' as it goes so that, + after 'getopt' is done, all the options precede all the non-option + arguments and 'optind' points to the first non-option argument. + Or, it can report non-option arguments as if they were arguments to + the option character '\x01'. + + The default behavior of 'getopt_long' is to permute the argument list. + When this implementation is used standalone, the default behavior of + 'getopt' is to stop at the first non-option argument, but when it is + used as part of GNU libc it also permutes the argument list. In both + cases, setting the environment variable POSIXLY_CORRECT to any value + disables permutation. + + If the first character of the OPTSTRING argument to 'getopt' or + 'getopt_long' is '+', both functions will stop at the first + non-option argument. If it is '-', both functions will report + non-option arguments as arguments to the option character '\x01'. */ + +#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; + +/* 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. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + 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; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + 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; + } + /* 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; +} + +/* Process the argument starting with d->__nextchar as a long option. + d->optind should *not* have been advanced over this argument. + + If the value returned is -1, it was not actually a long option, the + state is unchanged, and the argument should be processed as a set + of short options (this can only happen when long_only is true). + Otherwise, the option (and its argument, if any) have been consumed + and the return value is the value to return from _getopt_internal_r. */ +static int +process_long_option (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, struct _getopt_data *d, + int print_errors, const char *prefix) +{ + char *nameend; + size_t namelen; + const struct option *p; + const struct option *pfound = NULL; + int n_options; + int option_index; + + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + namelen = nameend - d->__nextchar; + + /* First look for an exact match, counting the options as a side + effect. */ + for (p = longopts, n_options = 0; p->name; p++, n_options++) + if (!strncmp (p->name, d->__nextchar, namelen) + && namelen == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + option_index = n_options; + break; + } + + if (pfound == NULL) + { + /* Didn't find an exact match, so look for abbreviations. */ + unsigned char *ambig_set = NULL; + int ambig_malloced = 0; + int ambig_fallback = 0; + int indfound = -1; + + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, namelen)) + { + 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. */ + if (!ambig_fallback) + { + if (!print_errors) + /* Don't waste effort tracking the ambig set if + we're not going to print it anyway. */ + ambig_fallback = 1; + else if (!ambig_set) + { + if (__libc_use_alloca (n_options)) + ambig_set = alloca (n_options); + else if ((ambig_set = malloc (n_options)) == NULL) + /* Fall back to simpler error message. */ + ambig_fallback = 1; + else + ambig_malloced = 1; + + if (ambig_set) + { + memset (ambig_set, 0, n_options); + ambig_set[indfound] = 1; + } + } + if (ambig_set) + ambig_set[option_index] = 1; + } + } + } + + if (ambig_set || ambig_fallback) + { + if (print_errors) + { + if (ambig_fallback) + fprintf (stderr, _("%s: option '%s%s' is ambiguous\n"), + argv[0], prefix, d->__nextchar); + else + { + flockfile (stderr); + fprintf (stderr, + _("%s: option '%s%s' is ambiguous; possibilities:"), + argv[0], prefix, d->__nextchar); + + for (option_index = 0; option_index < n_options; option_index++) + if (ambig_set[option_index]) + fprintf (stderr, " '%s%s'", + prefix, longopts[option_index].name); + + /* This must use 'fprintf' even though it's only + printing a single character, so that it goes through + __fxprintf_nocancel when compiled as part of glibc. */ + fprintf (stderr, "\n"); + funlockfile (stderr); + } + } + if (ambig_malloced) + free (ambig_set); + d->__nextchar += strlen (d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + + option_index = indfound; + } + + if (pfound == NULL) + { + /* 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. */ + if (!long_only || argv[d->optind][1] == '-' + || strchr (optstring, *d->__nextchar) == NULL) + { + if (print_errors) + fprintf (stderr, _("%s: unrecognized option '%s%s'\n"), + argv[0], prefix, d->__nextchar); + + d->__nextchar = NULL; + d->optind++; + d->optopt = 0; + return '?'; + } + + /* Otherwise interpret it as a short option. */ + return -1; + } + + /* We have found a matching long option. Consume it. */ + d->optind++; + d->__nextchar = NULL; + 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) + fprintf (stderr, + _("%s: option '%s%s' doesn't allow an argument\n"), + argv[0], prefix, pfound->name); + + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option '%s%s' requires an argument\n"), + argv[0], prefix, pfound->name); + + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; +} + +/* Initialize internal data upon the first call to getopt. */ + +static const char * +_getopt_initialize (int argc _GL_UNUSED, + char **argv _GL_UNUSED, const char *optstring, + struct _getopt_data *d, int posixly_correct) +{ + /* 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. */ + if (d->optind == 0) + d->optind = 1; + + d->__first_nonopt = d->__last_nonopt = d->optind; + d->__nextchar = NULL; + + /* 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 (posixly_correct || !!getenv ("POSIXLY_CORRECT")) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + + d->__initialized = 1; + 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 **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, struct _getopt_data *d, int posixly_correct) +{ + int print_errors = d->opterr; + + if (argc < 1) + return -1; + + d->optarg = NULL; + + if (d->optind == 0 || !d->__initialized) + optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct); + else if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + if (optstring[0] == ':') + print_errors = 0; + + /* Test whether ARGV[optind] points to a non-option argument. */ +#define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') + + 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 (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 (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. + Check whether it might be a long option. */ + if (longopts) + { + if (argv[d->optind][1] == '-') + { + /* "--foo" is always a long option. The special option + "--" was handled above. */ + d->__nextchar = argv[d->optind] + 2; + return process_long_option (argc, argv, optstring, longopts, + longind, long_only, d, + print_errors, "--"); + } + + /* 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 (long_only && (argv[d->optind][2] + || !strchr (optstring, argv[d->optind][1]))) + { + int code; + d->__nextchar = argv[d->optind] + 1; + code = process_long_option (argc, argv, optstring, longopts, + longind, long_only, d, + print_errors, "-"); + if (code != -1) + return code; + } + } + + /* It is not a long option. Skip the initial punctuation. */ + d->__nextchar = argv[d->optind] + 1; + } + + /* Look at and handle the next short option-character. */ + + { + char c = *d->__nextchar++; + const 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 == ':' || c == ';') + { + if (print_errors) + fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c); + d->optopt = c; + return '?'; + } + + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';' && longopts != NULL) + { + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + d->optarg = d->__nextchar; + else if (d->optind == argc) + { + if (print_errors) + fprintf (stderr, + _("%s: option requires an argument -- '%c'\n"), + argv[0], c); + + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + d->optarg = argv[d->optind]; + + d->__nextchar = d->optarg; + d->optarg = NULL; + return process_long_option (argc, argv, optstring, longopts, longind, + 0 /* long_only */, d, print_errors, "-W "); + } + 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) + fprintf (stderr, + _("%s: option requires an argument -- '%c'\n"), + argv[0], c); + + 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 **argv, const char *optstring, + const struct option *longopts, int *longind, int long_only, + int posixly_correct) +{ + int result; + + getopt_data.optind = optind; + getopt_data.opterr = opterr; + + result = _getopt_internal_r (argc, argv, optstring, longopts, + longind, long_only, &getopt_data, + posixly_correct); + + optind = getopt_data.optind; + optarg = getopt_data.optarg; + optopt = getopt_data.optopt; + + return result; +} + +/* glibc gets a LSB-compliant getopt and a POSIX-complaint __posix_getopt. + Standalone applications just get a POSIX-compliant getopt. + POSIX and LSB both require these functions to take 'char *const *argv' + even though this is incorrect (because of the permutation). */ +#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT) \ + int \ + NAME (int argc, char *const *argv, const char *optstring) \ + { \ + return _getopt_internal (argc, (char **)argv, optstring, \ + 0, 0, 0, POSIXLY_CORRECT); \ + } + +#ifdef _LIBC +GETOPT_ENTRY(getopt, 0) +GETOPT_ENTRY(__posix_getopt, 1) +#else +GETOPT_ENTRY(getopt, 1) +#endif + + +#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/REORG.TODO/posix/getopt.h b/REORG.TODO/posix/getopt.h new file mode 100644 index 0000000000..d9db3a6b4c --- /dev/null +++ b/REORG.TODO/posix/getopt.h @@ -0,0 +1,38 @@ +/* Declarations for getopt. + Copyright (C) 1989-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Unlike the bulk of the getopt implementation, this file is NOT part + of gnulib; gnulib also has a getopt.h but it is different. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#include <features.h> + +/* The type of the 'argv' argument to getopt_long and getopt_long_only + is properly 'char **', since both functions may write to the array + (in order to move all the options to the beginning). However, for + compatibility with old versions of LSB, glibc has to use 'char *const *' + instead. */ +#ifndef __getopt_argv_const +# define __getopt_argv_const const +#endif + +#include <bits/getopt_core.h> +#include <bits/getopt_ext.h> + +#endif /* getopt.h */ diff --git a/REORG.TODO/posix/getopt1.c b/REORG.TODO/posix/getopt1.c new file mode 100644 index 0000000000..526dc315cc --- /dev/null +++ b/REORG.TODO/posix/getopt1.c @@ -0,0 +1,159 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBC +# include <config.h> +#endif + +#include "getopt.h" +#include "getopt_int.h" + +int +getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 0, 0); +} + +int +_getopt_long_r (int argc, char **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, 0); +} + +/* 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 *__getopt_argv_const *argv, + const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 1, 0); +} + +int +_getopt_long_only_r (int argc, char **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, 0); +} + + +#ifdef TEST + +#include <stdio.h> +#include <stdlib.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 const 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/REORG.TODO/posix/getopt_int.h b/REORG.TODO/posix/getopt_int.h new file mode 100644 index 0000000000..9a18d5d4e6 --- /dev/null +++ b/REORG.TODO/posix/getopt_int.h @@ -0,0 +1,118 @@ +/* Internal declarations for getopt. + Copyright (C) 1989-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library and is also part of gnulib. + Patches to this file should be submitted to both projects. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GETOPT_INT_H +#define _GETOPT_INT_H 1 + +#include <getopt.h> + +extern int _getopt_internal (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct); + + +/* Reentrant versions which can handle parsing multiple argument + vectors at the same time. */ + +/* Describe how to deal with options that follow non-option ARGV-elements. + + REQUIRE_ORDER means don't recognize them as options; stop option + processing when the first non-option is seen. This is what POSIX + specifies should happen. + + PERMUTE means 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. + + 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 __ord + { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER + }; + +/* 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; + + /* See __ord above. */ + enum __ord __ordering; + + /* 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; +}; + +/* 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 **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, struct _getopt_data *__data, + int __posixly_correct); + +extern int _getopt_long_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + struct _getopt_data *__data); + +extern int _getopt_long_only_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, + int *__longind, + struct _getopt_data *__data); + +#endif /* getopt_int.h */ diff --git a/REORG.TODO/posix/getpgid.c b/REORG.TODO/posix/getpgid.c new file mode 100644 index 0000000000..f1c1630bf0 --- /dev/null +++ b/REORG.TODO/posix/getpgid.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/types.h> + +/* Get the process group ID of process PID. */ +pid_t +__getpgid (pid_t pid) +{ + return pid; +} +libc_hidden_def (__getpgid) +weak_alias (__getpgid, getpgid) + +stub_warning (getpgid) diff --git a/REORG.TODO/posix/getpgrp.c b/REORG.TODO/posix/getpgrp.c new file mode 100644 index 0000000000..26187e93ec --- /dev/null +++ b/REORG.TODO/posix/getpgrp.c @@ -0,0 +1,26 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/getpid.c b/REORG.TODO/posix/getpid.c new file mode 100644 index 0000000000..e7f045d0c3 --- /dev/null +++ b/REORG.TODO/posix/getpid.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Get the process ID of the calling process. */ +int +__getpid (void) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__getpid) +stub_warning (getpid) + +weak_alias (__getpid, getpid) +libc_hidden_weak (getpid) diff --git a/REORG.TODO/posix/getppid.c b/REORG.TODO/posix/getppid.c new file mode 100644 index 0000000000..a0e5d468eb --- /dev/null +++ b/REORG.TODO/posix/getppid.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + + +/* Get the parent process ID of the calling process. */ +int +__getppid (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getppid) + +weak_alias (__getppid, getppid) diff --git a/REORG.TODO/posix/getresgid.c b/REORG.TODO/posix/getresgid.c new file mode 100644 index 0000000000..ee61a7a41b --- /dev/null +++ b/REORG.TODO/posix/getresgid.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/getresuid.c b/REORG.TODO/posix/getresuid.c new file mode 100644 index 0000000000..0dab79cef0 --- /dev/null +++ b/REORG.TODO/posix/getresuid.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/getsid.c b/REORG.TODO/posix/getsid.c new file mode 100644 index 0000000000..fb54c314c1 --- /dev/null +++ b/REORG.TODO/posix/getsid.c @@ -0,0 +1,30 @@ +/* getsid -- Return session ID of a process. Stub version. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/getuid.c b/REORG.TODO/posix/getuid.c new file mode 100644 index 0000000000..6643ca1d92 --- /dev/null +++ b/REORG.TODO/posix/getuid.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Get the real user ID of the calling process. */ +uid_t +__getuid (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getuid) + +weak_alias (__getuid, getuid) diff --git a/REORG.TODO/posix/glob.c b/REORG.TODO/posix/glob.c new file mode 100644 index 0000000000..c653809118 --- /dev/null +++ b/REORG.TODO/posix/glob.c @@ -0,0 +1,1729 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glob.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.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> + +#if defined HAVE_STDINT_H || defined _LIBC +# include <stdint.h> +#elif !defined UINTPTR_MAX +# define UINTPTR_MAX (~((size_t) 0)) +#endif + +#include <errno.h> +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +# include <dirent.h> +#else +# define dirent direct +# 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 + +#include <stdlib.h> +#include <string.h> +#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) __THROWNL; + +/* A representation of a directory entry which does not depend on the + layout of struct dirent, or the size of ino_t. */ +struct readdir_result +{ + const char *name; +# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE + uint8_t type; +# endif + bool skip_entry; +}; + +# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +/* Initializer based on the d_type member of struct dirent. */ +# define D_TYPE_TO_RESULT(source) (source)->d_type, + +/* True if the directory entry D might be a symbolic link. */ +static bool +readdir_result_might_be_symlink (struct readdir_result d) +{ + return d.type == DT_UNKNOWN || d.type == DT_LNK; +} + +/* True if the directory entry D might be a directory. */ +static bool +readdir_result_might_be_dir (struct readdir_result d) +{ + return d.type == DT_DIR || readdir_result_might_be_symlink (d); +} +# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ +# define D_TYPE_TO_RESULT(source) + +/* If we do not have type information, symbolic links and directories + are always a possibility. */ + +static bool +readdir_result_might_be_symlink (struct readdir_result d) +{ + return true; +} + +static bool +readdir_result_might_be_dir (struct readdir_result d) +{ + return true; +} + +# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ + +# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +/* Initializer for skip_entry. POSIX does not require that the d_ino + field be present, and some systems do not provide it. */ +# define D_INO_TO_RESULT(source) false, +# else +# define D_INO_TO_RESULT(source) (source)->d_ino == 0, +# endif + +/* Construct an initializer for a struct readdir_result object from a + struct dirent *. No copy of the name is made. */ +#define READDIR_RESULT_INITIALIZER(source) \ + { \ + source->d_name, \ + D_TYPE_TO_RESULT (source) \ + D_INO_TO_RESULT (source) \ + } + +#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ + +/* Call gl_readdir on STREAM. This macro can be overridden to reduce + type safety if an old interface version needs to be supported. */ +#ifndef GL_READDIR +# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream)) +#endif + +/* Extract name and type from directory entry. No copy of the name is + made. If SOURCE is NULL, result name is NULL. Keep in sync with + convert_dirent64 below. */ +static struct readdir_result +convert_dirent (const struct dirent *source) +{ + if (source == NULL) + { + struct readdir_result result = { NULL, }; + return result; + } + struct readdir_result result = READDIR_RESULT_INITIALIZER (source); + return result; +} + +#ifndef COMPILE_GLOB64 +/* Like convert_dirent, but works on struct dirent64 instead. Keep in + sync with convert_dirent above. */ +static struct readdir_result +convert_dirent64 (const struct dirent64 *source) +{ + if (source == NULL) + { + struct readdir_result result = { NULL, }; + return result; + } + struct readdir_result result = READDIR_RESULT_INITIALIZER (source); + return result; +} +#endif + + +#ifndef attribute_hidden +# define attribute_hidden +#endif + +static int glob_in_dir (const char *pattern, const char *directory, + int flags, int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used); +extern int __glob_pattern_type (const char *pattern, int quote) + attribute_hidden; + +#if !defined _LIBC || !defined GLOB_ONLY_P +static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; +static int collated_compare (const void *, const void *) __THROWNL; + + +/* Find the end of the sub-pattern in a brace expression. */ +static const char * +next_brace_sub (const char *cp, int flags) +{ + size_t 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 (const char *pattern, int flags, int (*errfunc) (const char *, int), + glob_t *pglob) +{ + const char *filename; + char *dirname = NULL; + size_t dirlen; + int status; + size_t oldcount; + int meta; + int dirname_modified; + int malloc_dirname = 0; + glob_t dirs; + int retval = 0; +#ifdef _LIBC + size_t alloca_used = 0; +#endif + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + __set_errno (EINVAL); + return -1; + } + + /* POSIX requires all slashes to be matched. This means that with + a trailing slash we must match only directories. */ + if (pattern[0] && pattern[strlen (pattern) - 1] == '/') + flags |= GLOB_ONLYDIR; + + 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_APPEND)) + { + pglob->gl_pathc = 0; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_pathv = NULL; + else + { + size_t i; + + if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) + return GLOB_NOSPACE; + + 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; + } + } + + 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; + char *onealt; + size_t pattern_len = strlen (pattern) - 1; +#ifdef _LIBC + int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len); + if (alloca_onealt) + onealt = alloca_account (pattern_len, alloca_used); + else +#endif + { + onealt = (char *) malloc (pattern_len); + if (onealt == NULL) + return GLOB_NOSPACE; + } + + /* 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. */ + illegal_brace: +#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +#endif + free (onealt); + flags &= ~GLOB_BRACE; + goto no_brace; + } + + /* 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. */ + goto illegal_brace; + } + /* 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. */ + 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) + { +#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +#endif + free (onealt); + 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); + } + +#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +#endif + free (onealt); + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + + no_brace: + oldcount = pglob->gl_pathc + pglob->gl_offs; + + /* 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 */ + dirname_modified = 0; + 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 = (char *) 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 + { + if (__glibc_unlikely (pattern[0] == '\0')) + { + dirs.gl_pathv = NULL; + goto no_matches; + } + + filename = pattern; +#ifdef _AMIGA + dirname = (char *) ""; +#else + dirname = (char *) "."; +#endif + dirlen = 0; + } + } + else if (filename == pattern + || (filename == pattern + 1 && pattern[0] == '\\' + && (flags & GLOB_NOESCAPE) == 0)) + { + /* "/pattern" or "\\/pattern". */ + dirname = (char *) "/"; + 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 +#ifdef _LIBC + if (__libc_use_alloca (alloca_used + dirlen + 1)) + newp = alloca_account (dirlen + 1, alloca_used); + else +#endif + { + newp = malloc (dirlen + 1); + if (newp == NULL) + return GLOB_NOSPACE; + malloc_dirname = 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 orig_flags = flags; + if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') + { + /* "pattern\\/". Remove the final backslash if it hasn't + been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; + + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + { + *(char *) &dirname[--dirlen] = '\0'; + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + } + } + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + else if (val == GLOB_NOMATCH && flags != orig_flags) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + oldcount = pglob->gl_pathc + pglob->gl_offs; + goto no_matches; + } + retval = val; + goto out; + } + } + +#ifndef VMS + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/' + || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' + && (dirname[2] == '\0' || dirname[2] == '/'))) + { + /* Look up home directory. */ + char *home_dir = getenv ("HOME"); + int malloc_home_dir = 0; +# 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 = alloca_account (buflen, alloca_used); + + 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 malloc_pwtmpbuf = 0; + int save = errno; + +# ifndef _LIBC + if (pwbuflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. + Try a moderate value. */ + pwbuflen = 1024; +# endif + if (__libc_use_alloca (alloca_used + pwbuflen)) + pwtmpbuf = alloca_account (pwbuflen, alloca_used); + else + { + pwtmpbuf = malloc (pwbuflen); + if (pwtmpbuf == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_pwtmpbuf = 1; + } + + while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) + != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + + if (!malloc_pwtmpbuf + && __libc_use_alloca (alloca_used + + 2 * pwbuflen)) + pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen, + 2 * pwbuflen, + alloca_used); + else + { + char *newp = realloc (malloc_pwtmpbuf + ? pwtmpbuf : NULL, + 2 * pwbuflen); + if (newp == NULL) + { + if (__glibc_unlikely (malloc_pwtmpbuf)) + free (pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } + pwtmpbuf = newp; + pwbuflen = 2 * pwbuflen; + malloc_pwtmpbuf = 1; + } + __set_errno (save); + } +# else + p = getpwnam (name); +# endif + if (p != NULL) + { + if (!malloc_pwtmpbuf) + home_dir = p->pw_dir; + else + { + size_t home_dir_len = strlen (p->pw_dir) + 1; + if (__libc_use_alloca (alloca_used + home_dir_len)) + home_dir = alloca_account (home_dir_len, + alloca_used); + else + { + home_dir = malloc (home_dir_len); + if (home_dir == NULL) + { + free (pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } + malloc_home_dir = 1; + } + memcpy (home_dir, p->pw_dir, home_dir_len); + + free (pwtmpbuf); + } + } + } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (flags & GLOB_TILDE_CHECK) + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + retval = GLOB_NOMATCH; + goto out; + } + else + home_dir = (char *) "~"; /* No luck. */ + } +# endif /* WINDOWS32 */ +# endif + /* Now construct the full directory. */ + if (dirname[1] == '\0') + { + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = home_dir; + dirlen = strlen (dirname); + malloc_dirname = malloc_home_dir; + } + else + { + char *newp; + size_t home_len = strlen (home_dir); + int use_alloca = __libc_use_alloca (alloca_used + + home_len + dirlen); + if (use_alloca) + newp = alloca_account (home_len + dirlen, alloca_used); + else + { + newp = malloc (home_len + dirlen); + if (newp == NULL) + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + retval = GLOB_NOSPACE; + goto out; + } + } + + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); + + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = newp; + dirlen += home_len - 1; + malloc_dirname = !use_alloca; + } + dirname_modified = 1; + } +# if !defined _AMIGA && !defined WINDOWS32 + else + { + char *end_name = strchr (dirname, '/'); + char *user_name; + int malloc_user_name = 0; + char *unescape = NULL; + + if (!(flags & GLOB_NOESCAPE)) + { + if (end_name == NULL) + { + unescape = strchr (dirname, '\\'); + if (unescape) + end_name = strchr (unescape, '\0'); + } + else + unescape = memchr (dirname, '\\', end_name - dirname); + } + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + if (__libc_use_alloca (alloca_used + (end_name - dirname))) + newp = alloca_account (end_name - dirname, alloca_used); + else + { + newp = malloc (end_name - dirname); + if (newp == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_user_name = 1; + } + if (unescape != NULL) + { + char *p = mempcpy (newp, dirname + 1, + unescape - dirname - 1); + char *q = unescape; + while (*q != '\0') + { + if (*q == '\\') + { + if (q[1] == '\0') + { + /* "~fo\\o\\" unescape to user_name "foo\\", + but "~fo\\o\\/" unescape to user_name + "foo". */ + if (filename == NULL) + *p++ = '\\'; + break; + } + ++q; + } + *p++ = *q++; + } + *p = '\0'; + } + else + *((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; + int malloc_pwtmpbuf = 0; + 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 + if (__libc_use_alloca (alloca_used + buflen)) + pwtmpbuf = alloca_account (buflen, alloca_used); + else + { + pwtmpbuf = malloc (buflen); + if (pwtmpbuf == NULL) + { + nomem_getpw: + if (__glibc_unlikely (malloc_user_name)) + free (user_name); + retval = GLOB_NOSPACE; + goto out; + } + malloc_pwtmpbuf = 1; + } + + while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + if (!malloc_pwtmpbuf + && __libc_use_alloca (alloca_used + 2 * buflen)) + pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen, + 2 * buflen, alloca_used); + else + { + char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL, + 2 * buflen); + if (newp == NULL) + { + if (__glibc_unlikely (malloc_pwtmpbuf)) + free (pwtmpbuf); + goto nomem_getpw; + } + pwtmpbuf = newp; + malloc_pwtmpbuf = 1; + } + __set_errno (save); + } +# else + p = getpwnam (user_name); +# endif + + if (__glibc_unlikely (malloc_user_name)) + free (user_name); + + /* If we found a home directory use this. */ + if (p != NULL) + { + size_t home_len = strlen (p->pw_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + malloc_dirname = 0; + + if (__libc_use_alloca (alloca_used + home_len + rest_len + 1)) + dirname = alloca_account (home_len + rest_len + 1, + alloca_used); + else + { + dirname = malloc (home_len + rest_len + 1); + if (dirname == NULL) + { + if (__glibc_unlikely (malloc_pwtmpbuf)) + free (pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } + malloc_dirname = 1; + } + *((char *) mempcpy (mempcpy (dirname, p->pw_dir, home_len), + end_name, rest_len)) = '\0'; + + dirlen = home_len + rest_len; + dirname_modified = 1; + + if (__glibc_unlikely (malloc_pwtmpbuf)) + free (pwtmpbuf); + } + else + { + if (__glibc_unlikely (malloc_pwtmpbuf)) + free (pwtmpbuf); + + 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) + || (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + ? ((*pglob->gl_stat) (dirname, &st) == 0 + && S_ISDIR (st.st_mode)) + : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode))))) + { + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > UINTPTR_MAX - (1 + 1) + || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *)) + { + nospace: + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + + new_gl_pathv + = (char **) realloc (pglob->gl_pathv, + (newcount + 1 + 1) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace; + pglob->gl_pathv = new_gl_pathv; + + if (flags & GLOB_MARK) + { + char *p; + pglob->gl_pathv[newcount] = malloc (dirlen + 2); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); + p[0] = '/'; + p[1] = '\0'; + } + else + { + 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; + } + + meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); + /* meta is 1 if correct glob pattern containing metacharacters. + If meta has bit (1 << 2) set, it means there was an unterminated + [ which we handle the same, using fnmatch. Broken unterminated + pattern bracket expressions ought to be rare enough that it is + not worth special casing them, fnmatch will do the right thing. */ + if (meta & 5) + { + /* The directory name contains metacharacters, so we + have to glob for the directory, and then glob for + the pattern in each directory found. */ + size_t i; + + if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') + { + /* "foo\\/bar". Remove the final backslash from dirname + if it has not been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; + + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + *(char *) &dirname[--dirlen] = '\0'; + } + + if (__glibc_unlikely ((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_NOESCAPE + | GLOB_ALTDIRFUNC)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); + if (status != 0) + { + if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) + return status; + goto no_matches; + } + + /* 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) + { + size_t 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, alloca_used); + 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: + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > UINTPTR_MAX - 2 + || newcount + 2 > ~((size_t) 0) / sizeof (char *)) + { + nospace2: + globfree (&dirs); + return GLOB_NOSPACE; + } + + new_gl_pathv = (char **) realloc (pglob->gl_pathv, + (newcount + 2) + * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace2; + 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 + { + size_t old_pathc = pglob->gl_pathc; + int orig_flags = flags; + + if (meta & 2) + { + char *p = strchr (dirname, '\\'), *q; + /* We need to unescape the dirname string. It is certainly + allocated by alloca, as otherwise filename would be NULL + or dirname wouldn't contain backslashes. */ + q = p; + do + { + if (*p == '\\') + { + *q = *++p; + --dirlen; + } + else + *q = *p; + ++q; + } + while (*p++ != '\0'); + dirname_modified = 1; + } + if (dirname_modified) + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + status = glob_in_dir (filename, dirname, flags, errfunc, pglob, + alloca_used); + if (status != 0) + { + if (status == GLOB_NOMATCH && flags != orig_flags + && pglob->gl_pathc + pglob->gl_offs == oldcount) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + goto no_matches; + } + 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 ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? ((*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); + } + + out: + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + return retval; +} +#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 (glob_t *pglob) +{ + if (pglob->gl_pathv != NULL) + { + size_t i; + for (i = 0; i < pglob->gl_pathc; ++i) + 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) +{ + 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 +int +__glob_pattern_type (const char *pattern, int quote) +{ + const char *p; + int ret = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote) + { + if (p[1] != '\0') + ++p; + ret |= 2; + } + break; + + case '[': + ret |= 4; + break; + + case ']': + if (ret & 4) + return 1; + break; + } + + return ret; +} + +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (const char *pattern, int quote) +{ + return __glob_pattern_type (pattern, quote) == 1; +} +# 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 +__attribute_noinline__ +link_exists2_p (const char *dir, size_t dirlen, const char *fname, + glob_t *pglob +# ifndef _LIBC + , int flags +# endif + ) +{ + size_t fnamelen = strlen (fname); + char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1); + struct stat st; +# ifndef _LIBC + struct_stat64 st64; +# endif + + mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1), + fname, fnamelen + 1); + +# ifdef _LIBC + return (*pglob->gl_stat) (fullname, &st) == 0; +# else + return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? (*pglob->gl_stat) (fullname, &st) + : __stat64 (fullname, &st64)) == 0); +# endif +} +# ifdef _LIBC +# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ + (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) \ + ? link_exists2_p (dirname, dirnamelen, fname, pglob) \ + : ({ struct stat64 st64; \ + __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; })) +# else +# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ + link_exists2_p (dirname, dirnamelen, fname, pglob, flags) +# endif +#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 alloca_used) +{ + size_t dirlen = strlen (directory); + void *stream = NULL; + struct globnames + { + struct globnames *next; + size_t count; + char *name[64]; + }; +#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0]) + struct globnames init_names; + struct globnames *names = &init_names; + struct globnames *names_alloca = &init_names; + size_t nfound = 0; + size_t cur = 0; + int meta; + int save; + + alloca_used += sizeof (init_names); + + init_names.next = NULL; + init_names.count = INITIAL_COUNT; + + meta = __glob_pattern_type (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; + } + else if (meta == 0) + { + /* Since we use the normal file functions we can also use stat() + to verify the file is there. */ + union + { + struct stat st; + struct_stat64 st64; + } ust; + size_t patlen = strlen (pattern); + int alloca_fullname = __libc_use_alloca (alloca_used + + dirlen + 1 + patlen + 1); + char *fullname; + if (alloca_fullname) + fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used); + else + { + fullname = malloc (dirlen + 1 + patlen + 1); + if (fullname == NULL) + return GLOB_NOSPACE; + } + + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); + if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? (*pglob->gl_stat) (fullname, &ust.st) + : __stat64 (fullname, &ust.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; + + if (__glibc_unlikely (!alloca_fullname)) + free (fullname); + } + else + { + stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? (*pglob->gl_opendir) (directory) + : opendir (directory)); + if (stream == NULL) + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + } + else + { +#ifdef _LIBC + int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? -1 : dirfd ((DIR *) stream)); +#endif + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#if defined _AMIGA || defined VMS + | FNM_CASEFOLD +#endif + ); + flags |= GLOB_MAGCHAR; + + while (1) + { + struct readdir_result d; + { + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + d = convert_dirent (GL_READDIR (pglob, stream)); + else + { +#ifdef COMPILE_GLOB64 + d = convert_dirent (__readdir (stream)); +#else + d = convert_dirent64 (__readdir64 (stream)); +#endif + } + } + if (d.name == NULL) + break; + if (d.skip_entry) + continue; + + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d)) + continue; + + if (fnmatch (pattern, d.name, fnm_flags) == 0) + { + /* If the file we found is a symlink we have to + make sure the target file exists. */ + if (!readdir_result_might_be_symlink (d) + || link_exists_p (dfd, directory, dirlen, d.name, + pglob, flags)) + { + if (cur == names->count) + { + struct globnames *newnames; + size_t count = names->count * 2; + size_t size = (sizeof (struct globnames) + + ((count - INITIAL_COUNT) + * sizeof (char *))); + if (__libc_use_alloca (alloca_used + size)) + newnames = names_alloca + = alloca_account (size, alloca_used); + else if ((newnames = malloc (size)) + == NULL) + goto memory_error; + newnames->count = count; + newnames->next = names; + names = newnames; + cur = 0; + } + names->name[cur] = strdup (d.name); + if (names->name[cur] == NULL) + goto memory_error; + ++cur; + ++nfound; + } + } + } + } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) + { + size_t len = strlen (pattern); + nfound = 1; + names->name[cur] = (char *) malloc (len + 1); + if (names->name[cur] == NULL) + goto memory_error; + *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; + } + + int result = GLOB_NOMATCH; + if (nfound != 0) + { + result = 0; + + if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs + || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound + || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1 + || (pglob->gl_pathc + pglob->gl_offs + nfound + 1 + > UINTPTR_MAX / sizeof (char *))) + goto memory_error; + + 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) + { + memory_error: + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + free (names->name[i]); + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == &init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + result = GLOB_NOSPACE; + } + else + { + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] + = names->name[i]; + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == &init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } + } + + if (stream != NULL) + { + save = errno; + if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) + (*pglob->gl_closedir) (stream); + else + closedir (stream); + __set_errno (save); + } + + return result; +} diff --git a/REORG.TODO/posix/glob.h b/REORG.TODO/posix/glob.h new file mode 100644 index 0000000000..b5bd9ac189 --- /dev/null +++ b/REORG.TODO/posix/glob.h @@ -0,0 +1,181 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GLOB_H +#define _GLOB_H 1 + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/* We need `size_t' for the following definitions. */ +#ifndef __size_t +typedef __SIZE_TYPE__ __size_t; +# if defined __USE_XOPEN || defined __USE_XOPEN2K8 +typedef __SIZE_TYPE__ size_t; +# 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_MISC +# 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 + +/* 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 +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/REORG.TODO/posix/glob64.c b/REORG.TODO/posix/glob64.c new file mode 100644 index 0000000000..6cb3d654a8 --- /dev/null +++ b/REORG.TODO/posix/glob64.c @@ -0,0 +1,52 @@ +/* Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/globtest.c b/REORG.TODO/posix/globtest.c new file mode 100644 index 0000000000..878ae33044 --- /dev/null +++ b/REORG.TODO/posix/globtest.c @@ -0,0 +1,118 @@ +/* Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/globtest.sh b/REORG.TODO/posix/globtest.sh new file mode 100755 index 0000000000..73f7ae31cc --- /dev/null +++ b/REORG.TODO/posix/globtest.sh @@ -0,0 +1,831 @@ +#!/bin/bash +# Test for glob(3). +# Copyright (C) 1997-2017 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, see +# <http://www.gnu.org/licenses/>. + +set -e + +common_objpfx=$1; shift +test_via_rtld_prefix=$1; shift +test_program_prefix=$1; shift +test_wrapper_env=$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 + +# Since we use `sort' we must make sure to use the same locale everywhere. +LC_ALL=C +export LC_ALL + +# Create the arena +testdir=${common_objpfx}posix/globtest-dir +testout=${common_objpfx}posix/globtest-out +rm -rf $testdir $testout +mkdir $testdir + +cleanup() { + chmod 777 $testdir/noread + rm -fr $testdir $testout +} + +trap cleanup 0 HUP INT QUIT TERM + +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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 + ${test_program_prefix} \ + ${common_objpfx}posix/globtest -E "$testdir" "noread/*" | + sort > $testout + cat <<"EOF" | $CMP - $testout >> $logfile || failed=1 +GLOB_ABORTED +EOF + + ${test_program_prefix} \ + ${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 +${test_program_prefix} \ +${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 + +mkdir $testdir/'dir3*' +echo 1 > $testdir/'dir3*'/file1 +mkdir $testdir/'dir4[a' +echo 2 > $testdir/'dir4[a'/file1 +echo 3 > $testdir/'dir4[a'/file2 +mkdir $testdir/'dir5[ab]' +echo 4 > $testdir/'dir5[ab]'/file1 +echo 5 > $testdir/'dir5[ab]'/file2 +mkdir $testdir/dir6 +echo 6 > $testdir/dir6/'file1[a' +echo 7 > $testdir/dir6/'file1[ab]' +failed=0 +v=`${test_program_prefix} \ + ${common_objpfx}posix/globtest "$testdir" 'dir3\*/file2'` +test "$v" != 'GLOB_NOMATCH' && echo "$v" >> $logfile && failed=1 +${test_program_prefix} \ +${common_objpfx}posix/globtest -c "$testdir" \ +'dir3\*/file1' 'dir3\*/file2' 'dir1/file\1_1' 'dir1/file\1_9' \ +'dir2\/' 'nondir\/' 'dir4[a/fil*1' 'di*r4[a/file2' 'dir5[ab]/file[12]' \ +'dir6/fil*[a' 'dir*6/file1[a' 'dir6/fi*l[ab]' 'dir*6/file1[ab]' \ +'dir6/file1[[.a.]*' | +sort > $testout +cat <<"EOF" | $CMP - $testout >> $logfile || failed=1 +`dir*6/file1[ab]' +`dir1/file1_1' +`dir1/file\1_9' +`dir2/' +`dir3*/file1' +`dir3\*/file2' +`dir4[a/file1' +`dir4[a/file2' +`dir5[ab]/file[12]' +`dir6/fi*l[ab]' +`dir6/file1[a' +`dir6/file1[a' +`dir6/file1[a' +`dir6/file1[ab]' +`nondir\/' +EOF +${test_wrapper_env} \ +HOME="$testdir" \ +${test_via_rtld_prefix} \ +${common_objpfx}posix/globtest -ct "$testdir" \ +'~/dir1/file1_1' '~/dir1/file1_9' '~/dir3\*/file1' '~/dir3\*/file2' \ +'~\/dir1/file1_2' | +sort > $testout +cat <<EOF | $CMP - $testout >> $logfile || failed=1 +\`$testdir/dir1/file1_1' +\`$testdir/dir1/file1_2' +\`$testdir/dir3*/file1' +\`~/dir1/file1_9' +\`~/dir3\\*/file2' +EOF +if eval test -d ~"$USER"/; then + user=`echo "$USER" | sed -n -e 's/^\([^\\]\)\([^\\][^\\]*\)$/~\1\\\\\2/p'` + if test -n "$user"; then + ${test_program_prefix} \ + ${common_objpfx}posix/globtest -ctq "$testdir" "$user/" | + sort > $testout + eval echo ~$USER/ | $CMP - $testout >> $logfile || failed=1 + ${test_program_prefix} \ + ${common_objpfx}posix/globtest -ctq "$testdir" "$user\\/" | + sort > $testout + eval echo ~$USER/ | $CMP - $testout >> $logfile || failed=1 + ${test_program_prefix} \ + ${common_objpfx}posix/globtest -ctq "$testdir" "$user" | + sort > $testout + eval echo ~$USER | $CMP - $testout >> $logfile || failed=1 + fi +fi +if test $failed -ne 0; then + echo "Escape tests failed" >> $logfile + result=1 +fi + +# Test GLOB_BRACE and GLIB_DOOFFS with malloc checking +failed=0 +${test_wrapper_env} \ +MALLOC_PERTURB_=65 \ +${test_via_rtld_prefix} \ +${common_objpfx}posix/globtest -b -o "$testdir" "file{1,2}" > $testout || failed=1 +cat <<"EOF" | $CMP - $testout >> $logfile || failed=1 +`abc' +`file1' +`file2' +EOF +if test $failed -ne 0; then + echo "GLOB_BRACE+GLOB_DOOFFS test failed" >> $logfile + result=1 +fi + +if test $result -eq 0; then + 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/REORG.TODO/posix/group_member.c b/REORG.TODO/posix/group_member.c new file mode 100644 index 0000000000..75ed2dbdb6 --- /dev/null +++ b/REORG.TODO/posix/group_member.c @@ -0,0 +1,49 @@ +/* `group_member' -- test if process is in a given group. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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_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/REORG.TODO/posix/init-posix.c b/REORG.TODO/posix/init-posix.c new file mode 100644 index 0000000000..0c2b717e6d --- /dev/null +++ b/REORG.TODO/posix/init-posix.c @@ -0,0 +1 @@ +/* Nothing to do. */ diff --git a/REORG.TODO/posix/nanosleep.c b/REORG.TODO/posix/nanosleep.c new file mode 100644 index 0000000000..60a93caf9b --- /dev/null +++ b/REORG.TODO/posix/nanosleep.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <time.h> + + +/* Pause execution for a number of nanoseconds. */ +int +__nanosleep (const struct timespec *requested_time, + struct timespec *remaining) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (nanosleep) + +libc_hidden_def (__nanosleep) +weak_alias (__nanosleep, nanosleep) diff --git a/REORG.TODO/posix/pathconf.c b/REORG.TODO/posix/pathconf.c new file mode 100644 index 0000000000..1fcbe066ef --- /dev/null +++ b/REORG.TODO/posix/pathconf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Get file-specific information about PATH. */ +long int +__pathconf (const char *path, int name) +{ + if (path == NULL) + { + __set_errno (EINVAL); + return -1; + } + return __fpathconf (0, name); +} + +weak_alias (__pathconf, pathconf) + +stub_warning (pathconf) diff --git a/REORG.TODO/posix/pause.c b/REORG.TODO/posix/pause.c new file mode 100644 index 0000000000..c7f4b2dd9f --- /dev/null +++ b/REORG.TODO/posix/pause.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (void) +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (pause) diff --git a/REORG.TODO/posix/posix-conf-vars.h b/REORG.TODO/posix/posix-conf-vars.h new file mode 100644 index 0000000000..5cb6a781fc --- /dev/null +++ b/REORG.TODO/posix/posix-conf-vars.h @@ -0,0 +1,48 @@ +/* Macros to check if a POSIX configuration variable is defined or set. + + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _POSIX_CONF_VARS_H +#define _POSIX_CONF_VARS_H + +/* The script gen-posix-conf-vars.awk generates the header + posix-conf-vars-def.h from the list file posix-conf-vars.list and defines + CONF_DEF_* macros for each entry in the list file set to either of + CONF_DEF_UNDEFINED, CONF_DEF_DEFINED_SET or CONF_DEF_DEFINED_UNSET. To + check configuration variables within glibc code, use the configuration macro + functions instead of checking for definitions of the macros. */ + +#include <posix-conf-vars-def.h> + +#define CONF_DEF_UNDEFINED 1 +#define CONF_DEF_DEFINED_SET 2 +#define CONF_DEF_DEFINED_UNSET 3 + +/* The configuration variable is not defined. */ +#define CONF_IS_UNDEFINED(conf) (CONF_DEF##conf == CONF_DEF_UNDEFINED) + +/* The configuration variable is defined. It may or may not be set. */ +#define CONF_IS_DEFINED(conf) (CONF_DEF##conf != CONF_DEF_UNDEFINED) + +/* The configuration variable is defined and set. */ +#define CONF_IS_DEFINED_SET(conf) (CONF_DEF##conf == CONF_DEF_DEFINED_SET) + +/* The configuration variable is defined but not set. */ +#define CONF_IS_DEFINED_UNSET(conf) (CONF_DEF##conf == CONF_DEF_DEFINED_UNSET) + +#endif diff --git a/REORG.TODO/posix/posix-conf-vars.list b/REORG.TODO/posix/posix-conf-vars.list new file mode 100644 index 0000000000..601bc2fd33 --- /dev/null +++ b/REORG.TODO/posix/posix-conf-vars.list @@ -0,0 +1,113 @@ +# Configuration variables identified by getconf. The heading of each section +# is of the format TYPE PREFIX SC_PREFIX with the opening curly brace on the +# same line. TYPE can either be SYSCONF, PATHCONF, CONFSTR or SPEC. In the +# absence of SC_PREFIX, _SC is used as the SC_PREFIX. Variable names are put +# one on each line with a curly brace on its own line ending the section. + +SPEC POSIX { + V6_ILP32_OFF32 + V6_ILP32_OFFBIG + V6_LP64_OFF64 + V6_LPBIG_OFFBIG + V7_ILP32_OFF32 + V7_ILP32_OFFBIG + V7_LP64_OFF64 + V7_LPBIG_OFFBIG +} + +SYSCONF POSIX { + ADVISORY_INFO + ARG_MAX + ASYNCHRONOUS_IO + BARRIERS + BASE + CHILD_MAX + C_LANG_SUPPORT + C_LANG_SUPPORT_R + CLOCK_SELECTION + CPUTIME + DEVICE_IO + DEVICE_SPECIFIC + DEVICE_SPECIFIC_R + FD_MGMT + FIFO + FILE_ATTRIBUTES + FILE_LOCKING + FILE_SYSTEM + FSYNC + JOB_CONTROL + MAPPED_FILES + MEMLOCK + MEMLOCK_RANGE + MEMORY_PROTECTION + MESSAGE_PASSING + MONOTONIC_CLOCK + MULTI_PROCESS + NETWORKING + NGROUPS_MAX + OPEN_MAX + PII + PII_INTERNET + PII_INTERNET_DGRAM + PII_INTERNET_STREAM + PII_OSI + PII_OSI_CLTS + PII_OSI_COTS + PII_OSI_M + PII_SOCKET + PII_XTI + PIPE + POLL + PRIORITIZED_IO + PRIORITY_SCHEDULING + READER_WRITER_LOCKS + REALTIME_SIGNALS + REGEXP + SAVED_IDS + SELECT + SEMAPHORES + SHARED_MEMORY_OBJECTS + SHELL + SIGNALS + SINGLE_PROCESS + SPAWN + SPIN_LOCKS + SPORADIC_SERVER + SSIZE_MAX + STREAM_MAX + SYNCHRONIZED_IO + SYSTEM_DATABASE + SYSTEM_DATABASE_R + THREAD_ATTR_STACKADDR + THREAD_ATTR_STACKSIZE + THREAD_CPUTIME + THREAD_PRIO_INHERIT + THREAD_PRIO_PROTECT + THREAD_PRIORITY_SCHEDULING + THREAD_PROCESS_SHARED + THREADS + THREAD_SAFE_FUNCTIONS + THREAD_SPORADIC_SERVER + TIMEOUTS + TIMERS + TRACE + TRACE_EVENT_FILTER + TRACE_INHERIT + TRACE_LOG + TYPED_MEMORY_OBJECTS + TZNAME_MAX + USER_GROUPS + USER_GROUPS_R + VERSION +# Additional variables not in getconf. + THREAD_DESTRUCTOR_ITERATIONS + IPV6 + RAW_SOCKETS +} + +SPEC XBS5 _SC_XBS5 { + ILP32_OFF32 + ILP32_OFFBIG + LP64_OFF64 + LPBIG_OFFBIG +} diff --git a/REORG.TODO/posix/posix-envs.def b/REORG.TODO/posix/posix-envs.def new file mode 100644 index 0000000000..fecbcfe2ab --- /dev/null +++ b/REORG.TODO/posix/posix-envs.def @@ -0,0 +1,154 @@ +/* Handle POSIX compilation environments that may or may not be present. + Copyright (C) 2012-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* Before including this file, the including file must have included + <bits/environments.h> (generally via <unistd.h>) and must have + defined the following macros, exactly one of which will be called + for each POSIX environment: + + KNOWN_PRESENT_ENVIRONMENT, for POSIX environments that are known to + be supported in this libc. + + KNOWN_ABSENT_ENVIRONMENT, for POSIX environments that are known not + to be supported on this system. + + UNKNOWN_ENVIRONMENT, for POSIX environments not supported in this + libc but possibly supported by another libc on the same system, + that can be selected using the same compiler but different + compilation options. + + Each macro has arguments (SC_PREFIX, ENV_PREFIX, SUFFIX). The + corresponding argument to sysconf is _SC_##SC_PREFIX##_##SUFFIX. + The environment name, as used with getconf, is + ENV_PREFIX##_##SUFFIX, and the corresponding macro is the same with + a leading "_". + + In addition, the macros START_ENV_GROUP and END_ENV_GROUP must be + defined. These are called with arguments V5, V6, V7 before and + after the relevant groups of environments. */ + +#define NEED_SPEC_ARRAY 0 +#include <posix-conf-vars.h> + +START_ENV_GROUP (V7) + +#if CONF_IS_DEFINED_SET (_POSIX_V7_ILP32_OFF32) +KNOWN_PRESENT_ENVIRONMENT (V7, POSIX_V7, ILP32_OFF32) +#elif CONF_IS_DEFINED (_POSIX_V7_ILP32_OFF32) +KNOWN_ABSENT_ENVIRONMENT (V7, POSIX_V7, ILP32_OFF32) +#else +UNKNOWN_ENVIRONMENT (V7, POSIX_V7, ILP32_OFF32) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V7_ILP32_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (V7, POSIX_V7, ILP32_OFFBIG) +#elif CONF_IS_DEFINED (_POSIX_V7_ILP32_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (V7, POSIX_V7, ILP32_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (V7, POSIX_V7, ILP32_OFFBIG) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V7_LP64_OFF64) +KNOWN_PRESENT_ENVIRONMENT (V7, POSIX_V7, LP64_OFF64) +#elif CONF_IS_DEFINED (_POSIX_V7_LP64_OFF64) +KNOWN_ABSENT_ENVIRONMENT (V7, POSIX_V7, LP64_OFF64) +#else +UNKNOWN_ENVIRONMENT (V7, POSIX_V7, LP64_OFF64) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V7_LPBIG_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (V7, POSIX_V7, LPBIG_OFFBIG) +#elif CONF_IS_DEFINED (_POSIX_V7_LPBIG_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (V7, POSIX_V7, LPBIG_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (V7, POSIX_V7, LPBIG_OFFBIG) +#endif + +END_ENV_GROUP (V7) + +START_ENV_GROUP (V6) + +#if CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFF32) +KNOWN_PRESENT_ENVIRONMENT (V6, POSIX_V6, ILP32_OFF32) +#elif CONF_IS_DEFINED (_POSIX_V6_ILP32_OFF32) +KNOWN_ABSENT_ENVIRONMENT (V6, POSIX_V6, ILP32_OFF32) +#else +UNKNOWN_ENVIRONMENT (V6, POSIX_V6, ILP32_OFF32) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (V6, POSIX_V6, ILP32_OFFBIG) +#elif CONF_IS_DEFINED (_POSIX_V6_ILP32_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (V6, POSIX_V6, ILP32_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (V6, POSIX_V6, ILP32_OFFBIG) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V6_LP64_OFF64) +KNOWN_PRESENT_ENVIRONMENT (V6, POSIX_V6, LP64_OFF64) +#elif CONF_IS_DEFINED (_POSIX_V6_LP64_OFF64) +KNOWN_ABSENT_ENVIRONMENT (V6, POSIX_V6, LP64_OFF64) +#else +UNKNOWN_ENVIRONMENT (V6, POSIX_V6, LP64_OFF64) +#endif + +#if CONF_IS_DEFINED_SET (_POSIX_V6_LPBIG_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (V6, POSIX_V6, LPBIG_OFFBIG) +#elif CONF_IS_DEFINED (_POSIX_V6_LPBIG_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (V6, POSIX_V6, LPBIG_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (V6, POSIX_V6, LPBIG_OFFBIG) +#endif + +END_ENV_GROUP (V6) + +START_ENV_GROUP (V5) + +#if CONF_IS_DEFINED_SET (_XBS5_ILP32_OFF32) +KNOWN_PRESENT_ENVIRONMENT (XBS5, XBS5, ILP32_OFF32) +#elif CONF_IS_DEFINED (_XBS5_ILP32_OFF32) +KNOWN_ABSENT_ENVIRONMENT (XBS5, XBS5, ILP32_OFF32) +#else +UNKNOWN_ENVIRONMENT (XBS5, XBS5, ILP32_OFF32) +#endif + +#if CONF_IS_DEFINED_SET (_XBS5_ILP32_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (XBS5, XBS5, ILP32_OFFBIG) +#elif CONF_IS_DEFINED (_XBS5_ILP32_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (XBS5, XBS5, ILP32_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (XBS5, XBS5, ILP32_OFFBIG) +#endif + +#if CONF_IS_DEFINED_SET (_XBS5_LP64_OFF64) +KNOWN_PRESENT_ENVIRONMENT (XBS5, XBS5, LP64_OFF64) +#elif CONF_IS_DEFINED (_XBS5_LP64_OFF64) +KNOWN_ABSENT_ENVIRONMENT (XBS5, XBS5, LP64_OFF64) +#else +UNKNOWN_ENVIRONMENT (XBS5, XBS5, LP64_OFF64) +#endif + +#if CONF_IS_DEFINED_SET (_XBS5_LPBIG_OFFBIG) +KNOWN_PRESENT_ENVIRONMENT (XBS5, XBS5, LPBIG_OFFBIG) +#elif CONF_IS_DEFINED (_XBS5_LPBIG_OFFBIG) +KNOWN_ABSENT_ENVIRONMENT (XBS5, XBS5, LPBIG_OFFBIG) +#else +UNKNOWN_ENVIRONMENT (XBS5, XBS5, LPBIG_OFFBIG) +#endif + +END_ENV_GROUP (V5) diff --git a/REORG.TODO/posix/posix_madvise.c b/REORG.TODO/posix/posix_madvise.c new file mode 100644 index 0000000000..19f2bad4dd --- /dev/null +++ b/REORG.TODO/posix/posix_madvise.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1994-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/pread.c b/REORG.TODO/posix/pread.c new file mode 100644 index 0000000000..aa130d6fcf --- /dev/null +++ b/REORG.TODO/posix/pread.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/pread64.c b/REORG.TODO/posix/pread64.c new file mode 100644 index 0000000000..c20e75c7a8 --- /dev/null +++ b/REORG.TODO/posix/pread64.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/ptestcases.h b/REORG.TODO/posix/ptestcases.h new file mode 100644 index 0000000000..506b1cce0f --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/pwrite.c b/REORG.TODO/posix/pwrite.c new file mode 100644 index 0000000000..2004f503b2 --- /dev/null +++ b/REORG.TODO/posix/pwrite.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/pwrite64.c b/REORG.TODO/posix/pwrite64.c new file mode 100644 index 0000000000..27461194bd --- /dev/null +++ b/REORG.TODO/posix/pwrite64.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/re_comp.h b/REORG.TODO/posix/re_comp.h new file mode 100644 index 0000000000..e530f24abe --- /dev/null +++ b/REORG.TODO/posix/re_comp.h @@ -0,0 +1,25 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/regcomp.c b/REORG.TODO/posix/regcomp.c new file mode 100644 index 0000000000..b724ee3389 --- /dev/null +++ b/REORG.TODO/posix/regcomp.c @@ -0,0 +1,3858 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> + +#ifdef _LIBC +# include <locale/weight.h> +#endif + +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 (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 (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 (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, bool 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) + { + re_charset_t *cset = dfa->nodes[node].opr.mbcset; + int i; + +# ifdef _LIBC + /* See if we have to try all bytes which start multiple 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' (and + it is caught by SIMPLE_BRACKET). */ + if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0 + && (cset->ncoll_syms || cset->nranges)) + { + 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); + } +# endif /* _LIBC */ + + /* See if we have to start the match at all multibyte characters, + i.e. where we would not find an invalid sequence. This only + applies to multibyte character sets; for single byte character + sets, the SIMPLE_BRACKET again suffices. */ + if (dfa->mb_cur_max > 1 + && (cset->nchar_classes || cset->non_match || cset->nranges +# ifdef _LIBC + || cset->nequiv_classes +# endif /* _LIBC */ + )) + { + unsigned char c = 0; + do + { + mbstate_t mbs; + memset (&mbs, 0, sizeof (mbs)); + if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2) + re_set_fastmap (fastmap, false, (int) c); + } + while (++c != 0); + } + + else + { + /* ... Else catch all bytes which can start the mbchars. */ + 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, false, *(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 (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 (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 (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 (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) +{ + dfa->word_ops_used = 1; + int i = 0; + int ch = 0; + if (BE (dfa->map_notascii == 0, 1)) + { + if (sizeof (dfa->word_char[0]) == 8) + { + /* The extra temporaries here avoid "implicitly truncated" + warnings in the case when this is dead code, i.e. 32-bit. */ + const uint64_t wc0 = UINT64_C (0x03ff000000000000); + const uint64_t wc1 = UINT64_C (0x07fffffe87fffffe); + dfa->word_char[0] = wc0; + dfa->word_char[1] = wc1; + i = 2; + } + else if (sizeof (dfa->word_char[0]) == 4) + { + dfa->word_char[0] = UINT32_C (0x00000000); + dfa->word_char[1] = UINT32_C (0x03ff0000); + dfa->word_char[2] = UINT32_C (0x87fffffe); + dfa->word_char[3] = UINT32_C (0x07fffffe); + i = 4; + } + else + abort (); + ch = 128; + + if (BE (dfa->is_utf8, 1)) + { + memset (&dfa->word_char[i], '\0', (SBC_MAX - ch) / 8); + return; + } + } + + for (; i < BITSET_WORDS; ++i) + for (int 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)) + { + reg_errcode_t err = re_node_set_merge (&init_nodes, + dfa->eclosures + + dest_idx); + if (err != REG_NOERROR) + return err; + 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.ctx_type) + { + case LINE_FIRST: + case LINE_LAST: + case BUF_FIRST: + case BUF_LAST: + break; + default: + /* Word anchors etc. cannot be handled. It's okay to test + opr.ctx_type since constraints (for all DFA nodes) are + created by ORing one or more opr.ctx_type values. */ + 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; + if (node->token.type == ANCHOR) + dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; + } + 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) + err = 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 the node is root_node itself, it means the epsilon closure + has a loop. Then tie it to the destination of the root_node. */ + if (org_node == root_node && clone_node != org_node) + { + ret = re_node_set_insert (dfa->edests + clone_node, org_dest); + if (BE (ret < 0, 0)) + return REG_ESPACE; + break; + } + /* In case the node has another constraint, append it. */ + constraint |= dfa->nodes[org_node].constraint; + 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 is no such 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 is a duplicated node which satisfies 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; + dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; + 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; + int i; + re_node_set eclosure; + int ret; + int 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; + + /* If the current node has constraints, duplicate all nodes + since they must inherit the constraints. */ + if (dfa->nodes[node].constraint + && dfa->edests[node].nelem + && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) + { + err = duplicate_node_closure (dfa, node, node, node, + dfa->nodes[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'. */ + err = re_node_set_merge (&eclosure, &eclosure_elem); + if (BE (err != REG_NOERROR, 0)) + return err; + /* 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); + } + } + + /* An epsilon closure includes itself. */ + ret = re_node_set_insert (&eclosure, node); + if (BE (ret < 0, 0)) + return REG_ESPACE; + 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 occurs, 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)) + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + 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)) + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + return NULL; + } + if (tree != NULL && exp != NULL) + { + bin_tree_t *newtree = create_tree (dfa, tree, exp, CONCAT); + if (newtree == NULL) + { + postorder (exp, free_tree, NULL); + postorder (tree, free_tree, NULL); + *err = REG_ESPACE; + return NULL; + } + tree = newtree; + } + 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) + { + bin_tree_t *dup_tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); + if (BE (*err != REG_NOERROR && dup_tree == NULL, 0)) + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + return NULL; + } + tree = dup_tree; + /* In BRE consecutive duplications are not allowed. */ + if ((syntax & RE_CONTEXT_INVALID_DUP) + && (token->type == OP_DUP_ASTERISK + || token->type == OP_OPEN_DUP_NUM)) + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + *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)) + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + *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) || token->type != OP_CLOSE_DUP_NUM, 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); + if (BE (elem == NULL, 0)) + goto parse_dup_op_espace; + 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 since 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 environment. + Seek the collating symbol entry corresponding to NAME. + Return the index of the symbol in the SYMB_TABLE, + or -1 if not found. */ + + auto inline int32_t + __attribute__ ((always_inline)) + seek_collating_symbol_entry (const unsigned char *name, size_t name_len) + { + int32_t elem; + + for (elem = 0; elem < table_size; elem++) + if (symb_table[2 * elem] != 0) + { + int32_t idx = symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx += 1 + extra[idx]; + if (/* Compare the length of the name. */ + name_len == extra[idx] + /* Compare the name. */ + && memcmp (name, &extra[idx + 1], name_len) == 0) + /* Yep, this is the entry. */ + return elem; + } + return -1; + } + + /* Local function for parse_bracket_exp used in _LIBC environment. + 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 (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) + { + if (nrules != 0) + 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 (elem != -1) + { + /* 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 (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 environment. + 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 since we may + update it. */ + + auto inline reg_errcode_t + __attribute__ ((always_inline)) + build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc, + bracket_elem_t *start_elem, bracket_elem_t *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 environment. + 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. */ + + auto inline reg_errcode_t + __attribute__ ((always_inline)) + build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, + int *coll_sym_alloc, 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 (elem != -1) + { + /* We found the entry. */ + idx = symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx += 1 + extra[idx]; + } + else if (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 */ + { + re_free (sbcset); +#ifdef RE_ENABLE_I18N + re_free (mbcset); +#endif + *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, '\n'); + 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; + start_elem.type = COLL_SYM; + 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; + end_elem.type = COLL_SYM; + 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 since 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; + /* 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 (table, indirect, extra, &cp, -1); + if (BE (idx1 == 0 || *cp != '\0', 0)) + /* This isn't a valid character. */ + return REG_ECOLLATE; + + /* Build single byte matcing table for this equivalence class. */ + len = weights[idx1 & 0xffffff]; + for (ch = 0; ch < SBC_MAX; ++ch) + { + char_buf[0] = ch; + cp = char_buf; + idx2 = findidx (table, indirect, extra, &cp, 1); +/* + idx2 = table[ch]; +*/ + if (idx2 == 0) + /* This isn't a valid character. */ + continue; + /* Compare only if the length matches and the collation rule + index is the same. */ + if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24)) + { + int cnt = 0; + + while (cnt <= len && + weights[(idx1 & 0xffffff) + 1 + cnt] + == weights[(idx2 & 0xffffff) + 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 since 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 + 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/REORG.TODO/posix/regex.c b/REORG.TODO/posix/regex.c new file mode 100644 index 0000000000..02a486c29a --- /dev/null +++ b/REORG.TODO/posix/regex.c @@ -0,0 +1,76 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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> + +/* This header defines the MIN and MAX macros. */ +#include <sys/param.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/REORG.TODO/posix/regex.h b/REORG.TODO/posix/regex.h new file mode 100644 index 0000000000..3f0d6ce234 --- /dev/null +++ b/REORG.TODO/posix/regex.h @@ -0,0 +1,581 @@ +/* Definitions for data structures and routines for the regular + expression library. + Copyright (C) 1985, 1989-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + +#ifdef __USE_GNU +/* 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) +#endif + +/* 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; + +#ifdef __USE_GNU +/* 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_CHAR_CLASSES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INVALID_INTERVAL_ORD) \ + & ~(RE_DOT_NOT_NULL | 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 \ + | RE_INVALID_INTERVAL_ORD) + +#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) +#endif + + +/* 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 +{ +#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K + 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', + and `translate' can be set. After the pattern has been compiled, + the fields `re_nsub', `not_bol' and `not_eol' are available. All + other fields are private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define __RE_TRANSLATE_TYPE unsigned char * +# ifdef __USE_GNU +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE +# endif +#endif + +#ifdef __USE_GNU +# define __REPB_PREFIX(name) name +#else +# define __REPB_PREFIX(name) __##name +#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 *__REPB_PREFIX(buffer); + + /* Number of bytes to which `buffer' points. */ + unsigned long int __REPB_PREFIX(allocated); + + /* Number of bytes actually used in `buffer'. */ + unsigned long int __REPB_PREFIX(used); + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t __REPB_PREFIX(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 *__REPB_PREFIX(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 __REPB_PREFIX(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 __REPB_PREFIX(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. */ +#ifdef __USE_GNU +# define REGS_UNALLOCATED 0 +# define REGS_REALLOCATE 1 +# define REGS_FIXED 2 +#endif + unsigned __REPB_PREFIX(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 __REPB_PREFIX(fastmap_accurate) : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned __REPB_PREFIX(no_sub) : 1; + + /* If set, a beginning-of-line anchor doesn't match at the beginning + of the string. */ + unsigned __REPB_PREFIX(not_bol) : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned __REPB_PREFIX(not_eol) : 1; + + /* If true, an anchor at a newline matches. */ + unsigned __REPB_PREFIX(newline_anchor) : 1; +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +#ifdef __USE_GNU +/* 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 +#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. */ + +#ifdef __USE_GNU +/* 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. + + To free the allocated storage, you must call `regfree' on BUFFER. + Note that the translate table must either have been initialised by + `regcomp', with a malloc'ed value, or set to NULL before calling + `regfree'. */ +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); +#endif /* Use GNU */ + +#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_MISC) +# 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/REORG.TODO/posix/regex_internal.c b/REORG.TODO/posix/regex_internal.c new file mode 100644 index 0000000000..efafd173b3 --- /dev/null +++ b/REORG.TODO/posix/regex_internal.c @@ -0,0 +1,1732 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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; + + /* Avoid overflow in realloc. */ + const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int)); + if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) + return REG_ESPACE; + + 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) -1 || mbclen == 0 + || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len), 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; + } + else if (BE (mbclen == (size_t) -2, 0)) + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state = prev_st; + break; + } + + /* 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 __attribute_warn_unused_result__ +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 + || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len)) + { + /* It is an invalid character, an incomplete character + at the end of the string, 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 + || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len)) + { + /* 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; + wint_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;) + { + wchar_t wc2; + int remain_len = pstr->raw_len - rawbuf_idx; + prev_st = pstr->cur_state; + mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, + remain_len, &pstr->cur_state); + if (BE ((ssize_t) 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; + } + else + wc = (wint_t) wc2; + /* Then proceed the next character. */ + rawbuf_idx += mbclen; + } + *last_wc = 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 __attribute_warn_unused_result__ +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)) + { + /* Should the already checked characters be kept? */ + if (BE (offset < pstr->valid_raw_len, 1)) + { + /* Yes, move them to the front of the buffer. */ +#ifdef RE_ENABLE_I18N + if (BE (pstr->offsets_needed, 0)) + { + int low = 0, high = pstr->valid_len, mid; + do + { + mid = (high + low) / 2; + if (pstr->offsets[mid] > offset) + high = mid; + else if (pstr->offsets[mid] < offset) + low = mid + 1; + else + break; + } + while (low < high); + if (pstr->offsets[mid] < offset) + ++mid; + pstr->tip_context = re_string_context_at (pstr, mid - 1, + eflags); + /* This can be quite complicated, so handle specially + only the common and easy case where the character with + different length representation of lower and upper + case is present at or after offset. */ + if (pstr->valid_len > offset + && mid == offset && pstr->offsets[mid] == offset) + { + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); + memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; + for (low = 0; low < pstr->valid_len; low++) + pstr->offsets[low] = pstr->offsets[low + offset] - offset; + } + else + { + /* Otherwise, just find out how long the partial multibyte + character at offset is and fill it with WEOF/255. */ + pstr->len = pstr->raw_len - idx + offset; + pstr->stop = pstr->raw_stop - idx + offset; + pstr->offsets_needed = 0; + while (mid > 0 && pstr->offsets[mid - 1] == offset) + --mid; + while (mid < pstr->valid_len) + if (pstr->wcs[mid] != WEOF) + break; + else + ++mid; + if (mid == pstr->valid_len) + pstr->valid_len = 0; + else + { + pstr->valid_len = pstr->offsets[mid] - offset; + if (pstr->valid_len) + { + for (low = 0; low < pstr->valid_len; ++low) + pstr->wcs[low] = WEOF; + memset (pstr->mbs, 255, pstr->valid_len); + } + } + pstr->valid_raw_len = pstr->valid_len; + } + } + else +#endif + { + 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 defined DEBUG && DEBUG + assert (pstr->valid_len > 0); +#endif + } + } + else + { + /* No, skip all characters until IDX. */ + int prev_valid_len = pstr->valid_len; + +#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, *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); + if (end < pstr->raw_mbs) + end = pstr->raw_mbs; + 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; + + const unsigned char *pp = p; + if (BE (pstr->trans != NULL, 0)) + { + int i = mlen < 6 ? mlen : 6; + while (--i >= 0) + buf[i] = pstr->trans[p[i]]; + pp = 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 *) pp, 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, prev_valid_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 +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) + { +#if defined DEBUG && 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 in realloc. */ + const size_t max_object_size = MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + sizeof (int))); + if (BE (SIZE_MAX / max_object_size < new_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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 +__attribute_warn_unused_result__ +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)) + if (re_node_set_insert_last (&newstate->non_eps_nodes, elem) < 0) + return REG_ESPACE; + } + + 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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++) + { + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + unsigned int 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; + + 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; + } + if (re_node_set_init_copy (newstate->entrance_nodes, nodes) + != REG_NOERROR) + return NULL; + 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/REORG.TODO/posix/regex_internal.h b/REORG.TODO/posix/regex_internal.h new file mode 100644 index 0000000000..04317128b7 --- /dev/null +++ b/REORG.TODO/posix/regex_internal.h @@ -0,0 +1,766 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 <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/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) \ + __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_WCTYPE_H && HAVE_ISWCTYPE) || _LIBC +# define RE_ENABLE_I18N +#endif + +#if __GNUC__ >= 3 +# define BE(expr, val) __builtin_expect (expr, val) +#else +# define BE(expr, val) (expr) +#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 __mbrtowc mbrtowc +# define __mempcpy mempcpy +# define __wcrtomb wcrtomb +# define __regfree regfree +# define attribute_hidden +#endif /* not _LIBC */ + +#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1) +# 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 + +#if IS_IN (libc) +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 reg_errcode_t 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)); +#endif +#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 void __attribute__ ((unused)) +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 void __attribute__ ((unused)) +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 void __attribute__ ((unused)) +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 int +internal_function __attribute__ ((pure, unused)) +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 wint_t +internal_function __attribute__ ((pure, unused)) +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]; +} + +# if IS_IN (libc) +# ifdef _LIBC +# include <locale/weight.h> +# endif + +static int +internal_function __attribute__ ((pure, unused)) +re_string_elem_size_at (const re_string_t *pstr, int idx) +{ +# ifdef _LIBC + const unsigned char *p, *extra; + const int32_t *table, *indirect; + 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; + findidx (table, indirect, extra, &p, pstr->len - idx); + return p - pstr->mbs - idx; + } + else +# endif /* _LIBC */ + return 1; +} +# endif +#endif /* RE_ENABLE_I18N */ + +#endif /* _REGEX_INTERNAL_H */ diff --git a/REORG.TODO/posix/regexbug1.c b/REORG.TODO/posix/regexbug1.c new file mode 100644 index 0000000000..17643e7e4d --- /dev/null +++ b/REORG.TODO/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, "%s", 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, "%s", 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/REORG.TODO/posix/regexec.c b/REORG.TODO/posix/regexec.c new file mode 100644 index 0000000000..8eb09dcfa0 --- /dev/null +++ b/REORG.TODO/posix/regexec.c @@ -0,0 +1,4358 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> + +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, int min_len) + 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 (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 (struct re_pattern_buffer *bufp, const char *string, int length, + int 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 (struct re_pattern_buffer *bufp, const char *string, int length, + int start, int 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 (struct re_pattern_buffer *bufp, const char *string1, int length1, + const char *string2, int length2, int start, + struct re_registers *regs, int stop) +{ + 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 (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) +{ + 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 +internal_function +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) +{ + const char *str; + int rval; + int len = length1 + length2; + char *s = NULL; + + if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0)) + return -2; + + /* Concatenate the strings. */ + if (length2 > 0) + if (length1 > 0) + { + 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; + } + else + str = string2; + else + str = string1; + + rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); + re_free (s); + 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 +internal_function +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) +{ + 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 +internal_function +re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, + int 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); + if (BE (regs->start == NULL, 0)) + return REGS_UNALLOCATED; + regs->end = re_malloc (regoff_t, need_regs); + if (BE (regs->end == NULL, 0)) + { + re_free (regs->start); + 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; + if (BE (new_start == NULL, 0)) + return REGS_UNALLOCATED; + new_end = re_realloc (regs->end, regoff_t, need_regs); + if (BE (new_end == NULL, 0)) + { + re_free (new_start); + 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 (struct re_pattern_buffer *bufp, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *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 (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 +__attribute_warn_unused_result__ internal_function +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) +{ + 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) + { + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0)) + { + err = REG_ESPACE; + goto free_return; + } + + 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 +internal_function __attribute_warn_unused_result__ +prune_impossible_nodes (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; + + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0)) + return REG_ESPACE; + + 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; + if (sifted_states[0] == NULL) + { + ret = REG_NOMATCH; + 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 __attribute_warn_unused_result__ +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) + && mctx->input.bufs_len < mctx->input.len) + || (BE (next_char_idx >= mctx->input.valid_len, 0) + && mctx->input.valid_len < mctx->input.len)) + { + err = extend_buffers (mctx, next_char_idx + 1); + 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 + && mctx->input.bufs_len < mctx->input.len) + || (next_state_log_idx >= mctx->input.valid_len + && mctx->input.valid_len < mctx->input.len)) + { + reg_errcode_t err; + err = extend_buffers (mctx, next_state_log_idx + 1); + 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 __attribute_warn_unused_result__ +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++) + { + err = re_node_set_merge (&state->inveclosure, + dfa->inveclosures + dest_nodes->elems[i]); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + } + } + 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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, bkref_str_off + 1); + 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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); + if (BE (state->trtable == NULL, 0)) + return 0; + return 1; + } + return 0; + } + + err = re_node_set_alloc (&follows, ndests + 1); + if (BE (err != REG_NOERROR, 0)) + goto out_free; + + /* Avoid arithmetic overflow in size calculation. */ + if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests), + 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. */ + +# ifdef _LIBC +# include <locale/weight.h> +# endif + +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; + + /* 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); + int32_t idx = findidx (table, indirect, extra, &cp, elem_len); + 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 & 0xffffff]; + if (weight_len == weights[equiv_class_idx & 0xffffff] + && (idx >> 24) == (equiv_class_idx >> 24)) + { + int cnt = 0; + + idx &= 0xffffff; + equiv_class_idx &= 0xffffff; + + 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) * (*(int32_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 __attribute_warn_unused_result__ +extend_buffers (re_match_context_t *mctx, int min_len) +{ + reg_errcode_t ret; + re_string_t *pstr = &mctx->input; + + /* Avoid overflow. */ + if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0)) + return REG_ESPACE; + + /* Double the lengthes of the buffers, but allocate at least MIN_LEN. */ + ret = re_string_realloc_buffers (pstr, + MAX (min_len, + MIN (pstr->len, 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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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 __attribute_warn_unused_result__ +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/REORG.TODO/posix/runptests.c b/REORG.TODO/posix/runptests.c new file mode 100644 index 0000000000..100bae301b --- /dev/null +++ b/REORG.TODO/posix/runptests.c @@ -0,0 +1,122 @@ +/* POSIX regex testsuite from IEEE 2003.2. + Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/runtests.c b/REORG.TODO/posix/runtests.c new file mode 100644 index 0000000000..d44bf36266 --- /dev/null +++ b/REORG.TODO/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 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/REORG.TODO/posix/rxspencer/COPYRIGHT b/REORG.TODO/posix/rxspencer/COPYRIGHT new file mode 100644 index 0000000000..30c1f7a488 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/rxspencer/tests b/REORG.TODO/posix/rxspencer/tests new file mode 100644 index 0000000000..3ad46e2a61 --- /dev/null +++ b/REORG.TODO/posix/rxspencer/tests @@ -0,0 +1,542 @@ +# 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 + +o$($|.) - oN +o$($|.) - op +o$($|.) - o o diff --git a/REORG.TODO/posix/sched.h b/REORG.TODO/posix/sched.h new file mode 100644 index 0000000000..7037ab398d --- /dev/null +++ b/REORG.TODO/posix/sched.h @@ -0,0 +1,129 @@ +/* Definitions for POSIX 1003.1b-1993 (aka POSIX.4) scheduling interface. + Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SCHED_H +#define _SCHED_H 1 + +#include <features.h> + +/* Get type definitions. */ +#include <bits/types.h> + +#define __need_size_t +#define __need_NULL +#include <stddef.h> + +#include <bits/types/time_t.h> +#include <bits/types/struct_timespec.h> +#ifndef __USE_XOPEN2K +# include <time.h> +#endif + +#ifndef __pid_t_defined +typedef __pid_t pid_t; +# define __pid_t_defined +#endif + + +/* 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_S (cpu, sizeof (cpu_set_t), cpusetp) +# define CPU_CLR(cpu, cpusetp) __CPU_CLR_S (cpu, sizeof (cpu_set_t), cpusetp) +# define CPU_ISSET(cpu, cpusetp) __CPU_ISSET_S (cpu, sizeof (cpu_set_t), \ + cpusetp) +# define CPU_ZERO(cpusetp) __CPU_ZERO_S (sizeof (cpu_set_t), cpusetp) +# define CPU_COUNT(cpusetp) __CPU_COUNT_S (sizeof (cpu_set_t), cpusetp) + +# define CPU_SET_S(cpu, setsize, cpusetp) __CPU_SET_S (cpu, setsize, cpusetp) +# define CPU_CLR_S(cpu, setsize, cpusetp) __CPU_CLR_S (cpu, setsize, cpusetp) +# define CPU_ISSET_S(cpu, setsize, cpusetp) __CPU_ISSET_S (cpu, setsize, \ + cpusetp) +# define CPU_ZERO_S(setsize, cpusetp) __CPU_ZERO_S (setsize, cpusetp) +# define CPU_COUNT_S(setsize, cpusetp) __CPU_COUNT_S (setsize, cpusetp) + +# define CPU_EQUAL(cpusetp1, cpusetp2) \ + __CPU_EQUAL_S (sizeof (cpu_set_t), cpusetp1, cpusetp2) +# define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ + __CPU_EQUAL_S (setsize, cpusetp1, cpusetp2) + +# define CPU_AND(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, &) +# define CPU_OR(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, |) +# define CPU_XOR(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, ^) +# define CPU_AND_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, &) +# define CPU_OR_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, |) +# define CPU_XOR_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, ^) + +# define CPU_ALLOC_SIZE(count) __CPU_ALLOC_SIZE (count) +# define CPU_ALLOC(count) __CPU_ALLOC (count) +# define CPU_FREE(cpuset) __CPU_FREE (cpuset) + + +/* 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/REORG.TODO/posix/sched_cpualloc.c b/REORG.TODO/posix/sched_cpualloc.c new file mode 100644 index 0000000000..13a6de4ce9 --- /dev/null +++ b/REORG.TODO/posix/sched_cpualloc.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2007-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sched.h> +#include <stdlib.h> + + +cpu_set_t * +__sched_cpualloc (size_t count) +{ + return malloc (CPU_ALLOC_SIZE (count)); +} diff --git a/REORG.TODO/posix/sched_cpucount.c b/REORG.TODO/posix/sched_cpucount.c new file mode 100644 index 0000000000..eaddf61b1b --- /dev/null +++ b/REORG.TODO/posix/sched_cpucount.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2007-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <limits.h> +#include <sched.h> + + +int +__sched_cpucount (size_t setsize, const cpu_set_t *setp) +{ + int s = 0; + const __cpu_mask *p = setp->__bits; + const __cpu_mask *end = &setp->__bits[setsize / sizeof (__cpu_mask)]; + + while (p < end) + { + __cpu_mask l = *p++; + +#ifdef POPCNT + s += POPCNT (l); +#else + if (l == 0) + continue; + +# if LONG_BIT > 32 + l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); + l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); + l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); + l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); + l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); + l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); +# else + l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); + l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); + l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); + l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); + l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); +# endif + + s += l; +#endif + } + + return s; +} diff --git a/REORG.TODO/posix/sched_cpufree.c b/REORG.TODO/posix/sched_cpufree.c new file mode 100644 index 0000000000..f28332f87e --- /dev/null +++ b/REORG.TODO/posix/sched_cpufree.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2007-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sched.h> +#include <stdlib.h> + + +void +__sched_cpufree (cpu_set_t *set) +{ + free (set); +} diff --git a/REORG.TODO/posix/sched_getaffinity.c b/REORG.TODO/posix/sched_getaffinity.c new file mode 100644 index 0000000000..4b8664d73f --- /dev/null +++ b/REORG.TODO/posix/sched_getaffinity.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sched.h> +#include <sys/types.h> + + +/* Retrieve the CPU affinity mask for a particular process. */ +int +sched_getaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *cpuset) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_getaffinity) diff --git a/REORG.TODO/posix/sched_getp.c b/REORG.TODO/posix/sched_getp.c new file mode 100644 index 0000000000..4420ba021e --- /dev/null +++ b/REORG.TODO/posix/sched_getp.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_gets.c b/REORG.TODO/posix/sched_gets.c new file mode 100644 index 0000000000..d7fc09caf4 --- /dev/null +++ b/REORG.TODO/posix/sched_gets.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_primax.c b/REORG.TODO/posix/sched_primax.c new file mode 100644 index 0000000000..6f40b83f6c --- /dev/null +++ b/REORG.TODO/posix/sched_primax.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_primin.c b/REORG.TODO/posix/sched_primin.c new file mode 100644 index 0000000000..7e38a7cc6b --- /dev/null +++ b/REORG.TODO/posix/sched_primin.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_rr_gi.c b/REORG.TODO/posix/sched_rr_gi.c new file mode 100644 index 0000000000..f5d31fa5c2 --- /dev/null +++ b/REORG.TODO/posix/sched_rr_gi.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_setaffinity.c b/REORG.TODO/posix/sched_setaffinity.c new file mode 100644 index 0000000000..0a0b69a09e --- /dev/null +++ b/REORG.TODO/posix/sched_setaffinity.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sys/types.h> +#include <sched.h> + + +/* Retrieve the CPU affinity mask for a particular process. */ +int +sched_setaffinity (pid_t pid, size_t cpusetsize, const cpu_set_t *cpuset) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_setaffinity) diff --git a/REORG.TODO/posix/sched_setp.c b/REORG.TODO/posix/sched_setp.c new file mode 100644 index 0000000000..17c3af322a --- /dev/null +++ b/REORG.TODO/posix/sched_setp.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_sets.c b/REORG.TODO/posix/sched_sets.c new file mode 100644 index 0000000000..f0d42b74f9 --- /dev/null +++ b/REORG.TODO/posix/sched_sets.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/sched_yield.c b/REORG.TODO/posix/sched_yield.c new file mode 100644 index 0000000000..2a5077ae08 --- /dev/null +++ b/REORG.TODO/posix/sched_yield.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/setgid.c b/REORG.TODO/posix/setgid.c new file mode 100644 index 0000000000..374c91cf78 --- /dev/null +++ b/REORG.TODO/posix/setgid.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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_t gid) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setgid) + +weak_alias (__setgid, setgid) diff --git a/REORG.TODO/posix/setpgid.c b/REORG.TODO/posix/setpgid.c new file mode 100644 index 0000000000..9ad775c3ba --- /dev/null +++ b/REORG.TODO/posix/setpgid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (int pid, int pgid) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__setpgid) +stub_warning (setpgid) + +weak_alias (__setpgid, setpgid) diff --git a/REORG.TODO/posix/setpgrp.c b/REORG.TODO/posix/setpgrp.c new file mode 100644 index 0000000000..46ca1c9f8b --- /dev/null +++ b/REORG.TODO/posix/setpgrp.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +int +setpgrp (void) +{ + return __setpgid (0, 0); +} diff --git a/REORG.TODO/posix/setresgid.c b/REORG.TODO/posix/setresgid.c new file mode 100644 index 0000000000..231afb3daf --- /dev/null +++ b/REORG.TODO/posix/setresgid.c @@ -0,0 +1,33 @@ +/* setresgid -- set real group ID, effective group ID, and saved-set group ID + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/setresuid.c b/REORG.TODO/posix/setresuid.c new file mode 100644 index 0000000000..859e2811c4 --- /dev/null +++ b/REORG.TODO/posix/setresuid.c @@ -0,0 +1,33 @@ +/* setresuid -- set real user ID, effective user ID, and saved-set user ID + Copyright (C) 2002-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) diff --git a/REORG.TODO/posix/setsid.c b/REORG.TODO/posix/setsid.c new file mode 100644 index 0000000000..a7e4c7b943 --- /dev/null +++ b/REORG.TODO/posix/setsid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setsid) + +weak_alias (__setsid, setsid) diff --git a/REORG.TODO/posix/setuid.c b/REORG.TODO/posix/setuid.c new file mode 100644 index 0000000000..32f2ba6b6a --- /dev/null +++ b/REORG.TODO/posix/setuid.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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_t uid) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setuid) + +weak_alias (__setuid, setuid) diff --git a/REORG.TODO/posix/sleep.c b/REORG.TODO/posix/sleep.c new file mode 100644 index 0000000000..d97043e302 --- /dev/null +++ b/REORG.TODO/posix/sleep.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (unsigned int seconds) +{ + __set_errno (ENOSYS); + return seconds; +} +weak_alias (__sleep, sleep) + +stub_warning (sleep) diff --git a/REORG.TODO/posix/spawn.c b/REORG.TODO/posix/spawn.c new file mode 100644 index 0000000000..5267d0fde9 --- /dev/null +++ b/REORG.TODO/posix/spawn.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <spawn.h> +#include "spawn_int.h" +#include <shlib-compat.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); +} +versioned_symbol (libc, __posix_spawn, posix_spawn, GLIBC_2_15); + + +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +int +attribute_compat_text_section +__posix_spawn_compat (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, + SPAWN_XFLAGS_TRY_SHELL); +} +compat_symbol (libc, __posix_spawn_compat, posix_spawn, GLIBC_2_2); +#endif diff --git a/REORG.TODO/posix/spawn.h b/REORG.TODO/posix/spawn.h new file mode 100644 index 0000000000..2fa5f547c7 --- /dev/null +++ b/REORG.TODO/posix/spawn.h @@ -0,0 +1,190 @@ +/* Definitions for POSIX spawn interface. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SPAWN_H +#define _SPAWN_H 1 + +#include <features.h> +#include <sched.h> +#include <sys/types.h> +#include <bits/types/sigset_t.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 +# define POSIX_SPAWN_SETSID 0x80 +#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 point 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 point 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/REORG.TODO/posix/spawn_faction_addclose.c b/REORG.TODO/posix/spawn_faction_addclose.c new file mode 100644 index 0000000000..2aafdfd259 --- /dev/null +++ b/REORG.TODO/posix/spawn_faction_addclose.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) +{ + struct __spawn_action *rec; + + if (!__spawn_valid_fd (fd)) + 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/REORG.TODO/posix/spawn_faction_adddup2.c b/REORG.TODO/posix/spawn_faction_adddup2.c new file mode 100644 index 0000000000..9b41d78b56 --- /dev/null +++ b/REORG.TODO/posix/spawn_faction_adddup2.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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) +{ + struct __spawn_action *rec; + + if (!__spawn_valid_fd (fd) || !__spawn_valid_fd (newfd)) + 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/REORG.TODO/posix/spawn_faction_addopen.c b/REORG.TODO/posix/spawn_faction_addopen.c new file mode 100644 index 0000000000..cbb3584345 --- /dev/null +++ b/REORG.TODO/posix/spawn_faction_addopen.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.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) +{ + struct __spawn_action *rec; + + if (!__spawn_valid_fd (fd)) + return EBADF; + + char *path_copy = __strdup (path); + if (path_copy == NULL) + return ENOMEM; + + /* 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. */ + free (path_copy); + 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_copy; + 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/REORG.TODO/posix/spawn_faction_destroy.c b/REORG.TODO/posix/spawn_faction_destroy.c new file mode 100644 index 0000000000..48579a58ab --- /dev/null +++ b/REORG.TODO/posix/spawn_faction_destroy.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <spawn.h> +#include <stdlib.h> + +#include "spawn_int.h" + +/* Deallocate the file actions. */ +int +posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) +{ + /* Free the paths in the open actions. */ + for (int i = 0; i < file_actions->__used; ++i) + { + struct __spawn_action *sa = &file_actions->__actions[i]; + switch (sa->tag) + { + case spawn_do_open: + free (sa->action.open_action.path); + break; + case spawn_do_close: + case spawn_do_dup2: + /* No cleanup required. */ + break; + } + } + + /* Free the array of actions. */ + free (file_actions->__actions); + return 0; +} diff --git a/REORG.TODO/posix/spawn_faction_init.c b/REORG.TODO/posix/spawn_faction_init.c new file mode 100644 index 0000000000..1744b76626 --- /dev/null +++ b/REORG.TODO/posix/spawn_faction_init.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawn_int.h b/REORG.TODO/posix/spawn_int.h new file mode 100644 index 0000000000..c60eb948bb --- /dev/null +++ b/REORG.TODO/posix/spawn_int.h @@ -0,0 +1,71 @@ +/* Internal definitions for posix_spawn functionality. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SPAWN_INT_H +#define _SPAWN_INT_H + +#include <spawn.h> +#include <stdbool.h> + +/* 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; + char *path; + int oflag; + mode_t mode; + } open_action; + } action; +}; + +#define SPAWN_XFLAGS_USE_PATH 0x1 +#define SPAWN_XFLAGS_TRY_SHELL 0x2 + +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 xflags); + +/* Return true if FD falls into the range valid for file descriptors. + The check in this form is mandated by POSIX. */ +bool __spawn_valid_fd (int fd) internal_function attribute_hidden; + +#endif /* _SPAWN_INT_H */ diff --git a/REORG.TODO/posix/spawn_valid_fd.c b/REORG.TODO/posix/spawn_valid_fd.c new file mode 100644 index 0000000000..eacabfc56d --- /dev/null +++ b/REORG.TODO/posix/spawn_valid_fd.c @@ -0,0 +1,31 @@ +/* File descriptor validity check for posix_spawn file actions. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include "spawn_int.h" + +#include <unistd.h> + +bool +internal_function +__spawn_valid_fd (int fd) +{ + long maxfd = __sysconf (_SC_OPEN_MAX); + return __glibc_likely (fd >= 0) + && (__glibc_unlikely (maxfd < 0) /* No limit set. */ + || __glibc_likely (fd < maxfd)); +} diff --git a/REORG.TODO/posix/spawnattr_destroy.c b/REORG.TODO/posix/spawnattr_destroy.c new file mode 100644 index 0000000000..30735f89ce --- /dev/null +++ b/REORG.TODO/posix/spawnattr_destroy.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_getdefault.c b/REORG.TODO/posix/spawnattr_getdefault.c new file mode 100644 index 0000000000..0a9d395b25 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getdefault.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_getflags.c b/REORG.TODO/posix/spawnattr_getflags.c new file mode 100644 index 0000000000..c7408538f4 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getflags.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_getpgroup.c b/REORG.TODO/posix/spawnattr_getpgroup.c new file mode 100644 index 0000000000..baad51a569 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getpgroup.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_getschedparam.c b/REORG.TODO/posix/spawnattr_getschedparam.c new file mode 100644 index 0000000000..aba6c6155c --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getschedparam.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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->__sp)); + + return 0; +} diff --git a/REORG.TODO/posix/spawnattr_getschedpolicy.c b/REORG.TODO/posix/spawnattr_getschedpolicy.c new file mode 100644 index 0000000000..d78cd7c049 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getschedpolicy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_getsigmask.c b/REORG.TODO/posix/spawnattr_getsigmask.c new file mode 100644 index 0000000000..4b493fd200 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_getsigmask.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_init.c b/REORG.TODO/posix/spawnattr_init.c new file mode 100644 index 0000000000..e71fac7efe --- /dev/null +++ b/REORG.TODO/posix/spawnattr_init.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_setdefault.c b/REORG.TODO/posix/spawnattr_setdefault.c new file mode 100644 index 0000000000..5e84753b7e --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setdefault.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_setflags.c b/REORG.TODO/posix/spawnattr_setflags.c new file mode 100644 index 0000000000..62d2f00c20 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setflags.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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_SETSID \ + | 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/REORG.TODO/posix/spawnattr_setpgroup.c b/REORG.TODO/posix/spawnattr_setpgroup.c new file mode 100644 index 0000000000..5b66580563 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setpgroup.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_setschedparam.c b/REORG.TODO/posix/spawnattr_setschedparam.c new file mode 100644 index 0000000000..05a15fce90 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setschedparam.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_setschedpolicy.c b/REORG.TODO/posix/spawnattr_setschedpolicy.c new file mode 100644 index 0000000000..8f65a8d23d --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setschedpolicy.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawnattr_setsigmask.c b/REORG.TODO/posix/spawnattr_setsigmask.c new file mode 100644 index 0000000000..036b0eedf7 --- /dev/null +++ b/REORG.TODO/posix/spawnattr_setsigmask.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/spawni.c b/REORG.TODO/posix/spawni.c new file mode 100644 index 0000000000..46665bb617 --- /dev/null +++ b/REORG.TODO/posix/spawni.c @@ -0,0 +1,44 @@ +/* Guts of POSIX spawn interface. Stub version. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 xflags) +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (__spawni) diff --git a/REORG.TODO/posix/spawnp.c b/REORG.TODO/posix/spawnp.c new file mode 100644 index 0000000000..070c730d42 --- /dev/null +++ b/REORG.TODO/posix/spawnp.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <spawn.h> +#include "spawn_int.h" +#include <shlib-compat.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, + SPAWN_XFLAGS_USE_PATH); +} +versioned_symbol (libc, __posix_spawnp, posix_spawnp, GLIBC_2_15); + + +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +int +attribute_compat_text_section +__posix_spawnp_compat (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, + SPAWN_XFLAGS_USE_PATH | SPAWN_XFLAGS_TRY_SHELL); +} +compat_symbol (libc, __posix_spawnp_compat, posix_spawnp, GLIBC_2_2); +#endif diff --git a/REORG.TODO/posix/sys/times.h b/REORG.TODO/posix/sys/times.h new file mode 100644 index 0000000000..2b81860ce5 --- /dev/null +++ b/REORG.TODO/posix/sys/times.h @@ -0,0 +1,50 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * POSIX Standard: 4.5.2 Process Times <sys/times.h> + */ + +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H 1 + +#include <features.h> + +#include <bits/types/clock_t.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/REORG.TODO/posix/sys/types.h b/REORG.TODO/posix/sys/types.h new file mode 100644 index 0000000000..c6326b1910 --- /dev/null +++ b/REORG.TODO/posix/sys/types.h @@ -0,0 +1,259 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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_MISC +# 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_XOPEN || defined __USE_XOPEN2K8) \ + && !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_MISC +# ifndef __daddr_t_defined +typedef __daddr_t daddr_t; +typedef __caddr_t caddr_t; +# define __daddr_t_defined +# endif +#endif + +#if (defined __USE_MISC || defined __USE_XOPEN) && !defined __key_t_defined +typedef __key_t key_t; +# define __key_t_defined +#endif + +#if defined __USE_XOPEN || defined __USE_XOPEN2K8 +# include <bits/types/clock_t.h> +#endif +#include <bits/types/clockid_t.h> +#include <bits/types/time_t.h> +#include <bits/types/timer_t.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. */ + +#include <bits/stdint-intn.h> + +#if !__GNUC_PREREQ (2, 7) + +/* 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; +# else +__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 __u_intN_t(N, MODE) \ + typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE))) + +__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_MISC +/* 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 `major', `minor', and `makedev' in this header. + However, these symbols are likely to collide with user code, so we are + going to stop defining them here in an upcoming release. Code that needs + these macros should include <sys/sysmacros.h> directly. Code that does + not need these macros should #undef them after including this header. */ +# define __SYSMACROS_DEPRECATED_INCLUSION +# include <sys/sysmacros.h> +# undef __SYSMACROS_DEPRECATED_INCLUSION +#endif /* Use misc. */ + + +#if (defined __USE_UNIX98 || defined __USE_XOPEN2K8) \ + && !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/REORG.TODO/posix/sys/unistd.h b/REORG.TODO/posix/sys/unistd.h new file mode 100644 index 0000000000..1e823fbd53 --- /dev/null +++ b/REORG.TODO/posix/sys/unistd.h @@ -0,0 +1 @@ +#include <unistd.h> diff --git a/REORG.TODO/posix/sys/utsname.h b/REORG.TODO/posix/sys/utsname.h new file mode 100644 index 0000000000..84b75a16a6 --- /dev/null +++ b/REORG.TODO/posix/sys/utsname.h @@ -0,0 +1,86 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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_MISC +/* 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/REORG.TODO/posix/sys/wait.h b/REORG.TODO/posix/sys/wait.h new file mode 100644 index 0000000000..d5b7e4d8d4 --- /dev/null +++ b/REORG.TODO/posix/sys/wait.h @@ -0,0 +1,146 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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> + +/* These macros could also be defined in <stdlib.h>. */ +#if !defined _STDLIB_H || (!defined __USE_XOPEN && !defined __USE_XOPEN2K8) +/* This will define the `W*' macros for the flag + bits to `waitpid', `wait3', and `wait4'. */ +# include <bits/waitflags.h> + +/* This will define all the `__W*' macros. */ +# include <bits/waitstatus.h> + +# define WEXITSTATUS(status) __WEXITSTATUS (status) +# define WTERMSIG(status) __WTERMSIG (status) +# define WSTOPSIG(status) __WSTOPSIG (status) +# define WIFEXITED(status) __WIFEXITED (status) +# define WIFSIGNALED(status) __WIFSIGNALED (status) +# define WIFSTOPPED(status) __WIFSTOPPED (status) +# ifdef __WIFCONTINUED +# define WIFCONTINUED(status) __WIFCONTINUED (status) +# endif +#endif /* <stdlib.h> not included. */ + +#ifdef __USE_MISC +# define WCOREFLAG __WCOREFLAG +# define WCOREDUMP(status) __WCOREDUMP (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_XOPEN || defined __USE_XOPEN2K8 +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 (int *__stat_loc); + +#ifdef __USE_MISC +/* 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_XOPEN || defined __USE_XOPEN2K8 +# ifndef __id_t_defined +# include <bits/types.h> +typedef __id_t id_t; +# define __id_t_defined +# endif + +# include <bits/types/siginfo_t.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_MISC || 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 (int *__stat_loc, int __options, + struct rusage * __usage) __THROWNL; +#endif + +#ifdef __USE_MISC +/* PID is like waitpid. Other args are like wait3. */ +extern __pid_t wait4 (__pid_t __pid, int *__stat_loc, int __options, + struct rusage *__usage) __THROWNL; +#endif /* Use misc. */ + + +__END_DECLS + +#endif /* sys/wait.h */ diff --git a/REORG.TODO/posix/sysconf.c b/REORG.TODO/posix/sysconf.c new file mode 100644 index 0000000000..4e9ed9705f --- /dev/null +++ b/REORG.TODO/posix/sysconf.c @@ -0,0 +1,279 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (int name) +{ + switch (name) + { + default: + __set_errno (EINVAL); + return -1; + + case _SC_TZNAME_MAX: + return -1; + + 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_POSIX_V6_ILP32_OFF32: + case _SC_POSIX_V6_ILP32_OFFBIG: + case _SC_POSIX_V6_LP64_OFF64: + case _SC_POSIX_V6_LPBIG_OFFBIG: + + case _SC_POSIX_V7_ILP32_OFF32: + case _SC_POSIX_V7_ILP32_OFFBIG: + case _SC_POSIX_V7_LP64_OFF64: + case _SC_POSIX_V7_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) diff --git a/REORG.TODO/posix/tar.h b/REORG.TODO/posix/tar.h new file mode 100644 index 0000000000..f85a401bc7 --- /dev/null +++ b/REORG.TODO/posix/tar.h @@ -0,0 +1,112 @@ +/* Extended tar format from POSIX.1. + Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _TAR_H +#define _TAR_H 1 + +#include <features.h> + + +/* 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 +#if defined __USE_XOPEN || !defined __USE_XOPEN2K +# define TSVTX 01000 +#endif +#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/REORG.TODO/posix/test-errno.c b/REORG.TODO/posix/test-errno.c new file mode 100644 index 0000000000..6aa297f837 --- /dev/null +++ b/REORG.TODO/posix/test-errno.c @@ -0,0 +1,154 @@ +/* Test that failing system calls do set errno to the correct value. + + Copyright (C) 2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <grp.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/types.h> +#include <sys/statfs.h> +#include <sys/mman.h> +#include <sys/uio.h> +#include <unistd.h> +#include <netinet/in.h> + +/* This is not an exhaustive test: only system calls that can be + persuaded to fail with a consistent error code and no side effects + are included. Usually these are failures due to invalid arguments, + with errno code EBADF or EINVAL. The order of argument checks is + unspecified, so we must take care to provide arguments that only + allow _one_ failure mode. + + Note that all system calls that can fail with EFAULT are permitted + to deliver a SIGSEGV signal instead, so we avoid supplying invalid + pointers in general, and we do not attempt to test system calls + that can only fail with EFAULT (e.g. gettimeofday, gethostname). + + Also note that root-only system calls (e.g. acct, reboot) may, when + the test is run as an unprivileged user, fail due to insufficient + privileges before bothering to do argument checks, so those are not + tested either. + + Also, system calls that take enum or a set of flags as argument is + not tested if POSIX doesn't specify exact binary values for all + flags, and so any value passed to flags may become valid. + + Some tests assume "/bin/sh" names a file that exists and is not a + directory. */ + +#define test_wrp_rv(rtype, prtype, experr, syscall, ...) \ + (__extension__ ({ \ + errno = 0xdead; \ + rtype ret = syscall (__VA_ARGS__); \ + int err = errno; \ + int fail; \ + if (ret == (rtype) -1 && err == experr) \ + fail = 0; \ + else \ + { \ + fail = 1; \ + if (ret != (rtype) -1) \ + printf ("FAIL: " #syscall ": didn't fail as expected" \ + " (return "prtype")\n", ret); \ + else if (err == 0xdead) \ + puts("FAIL: " #syscall ": didn't update errno\n"); \ + else if (err != experr) \ + printf ("FAIL: " #syscall \ + ": errno is: %d (%s) expected: %d (%s)\n", \ + err, strerror (err), experr, strerror (experr)); \ + } \ + fail; \ + })) + +#define test_wrp(experr, syscall, ...) \ + test_wrp_rv(int, "%d", experr, syscall, __VA_ARGS__) + +static int +do_test (void) +{ + size_t pagesize = sysconf (_SC_PAGESIZE); + struct statfs sfs; + struct sockaddr sa; + socklen_t sl; + char buf[1]; + struct iovec iov[1] = { { buf, 1 } }; + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = htons (1026); + sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + struct msghdr msg; + memset(&msg, 0, sizeof msg); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + int fails = 0; + fails |= test_wrp (EBADF, accept, -1, &sa, &sl); + fails |= test_wrp (EINVAL, access, "/", -1); + fails |= test_wrp (EBADF, bind, -1, (struct sockaddr *)&sin, sizeof sin); + fails |= test_wrp (ENOTDIR, chdir, "/bin/sh"); + fails |= test_wrp (EBADF, close, -1); + fails |= test_wrp (EBADF, connect, -1, (struct sockaddr *)&sin, sizeof sin); + fails |= test_wrp (EBADF, dup, -1); + fails |= test_wrp (EBADF, dup2, -1, -1); + fails |= test_wrp (EBADF, fchdir, -1); + fails |= test_wrp (EBADF, fchmod, -1, 0); + fails |= test_wrp (EBADF, fcntl, -1, 0); + fails |= test_wrp (EBADF, fstatfs, -1, &sfs); + fails |= test_wrp (EBADF, fsync, -1); + fails |= test_wrp (EBADF, ftruncate, -1, 0); + fails |= test_wrp (EINVAL, getgroups, -1, 0); + fails |= test_wrp (EBADF, getpeername, -1, &sa, &sl); + fails |= test_wrp (EBADF, getsockname, -1, &sa, &sl); + fails |= test_wrp (EBADF, getsockopt, -1, 0, 0, buf, &sl); + fails |= test_wrp (EBADF, ioctl, -1, TIOCNOTTY); + fails |= test_wrp (EBADF, listen, -1, 1); + fails |= test_wrp (EBADF, lseek, -1, 0, 0); + fails |= test_wrp (EINVAL, madvise, (void *) -1, -1, 0); + fails |= test_wrp_rv (void *, "%p", EBADF, + mmap, 0, pagesize, PROT_READ, MAP_PRIVATE, -1, 0); + fails |= test_wrp (EINVAL, mprotect, (void *) -1, pagesize, -1); + fails |= test_wrp (EINVAL, msync, (void *) -1, pagesize, -1); + fails |= test_wrp (EINVAL, munmap, (void *) -1, 0); + fails |= test_wrp (EISDIR, open, "/bin", EISDIR, O_WRONLY); + fails |= test_wrp (EBADF, read, -1, buf, 1); + fails |= test_wrp (EINVAL, readlink, "/", buf, -1); + fails |= test_wrp (EBADF, readv, -1, iov, 1); + fails |= test_wrp (EBADF, recv, -1, buf, 1, 0); + fails |= test_wrp (EBADF, recvfrom, -1, buf, 1, 0, &sa, &sl); + fails |= test_wrp (EBADF, recvmsg, -1, &msg, 0); + fails |= test_wrp (EINVAL, select, -1, 0, 0, 0, 0); + fails |= test_wrp (EBADF, send, -1, buf, 1, 0); + fails |= test_wrp (EBADF, sendmsg, -1, &msg, 0); + fails |= test_wrp (EBADF, sendto, -1, buf, 1, 0, &sa, sl); + fails |= test_wrp (EBADF, setsockopt, -1, 0, 0, buf, sizeof (*buf)); + fails |= test_wrp (EBADF, shutdown, -1, SHUT_RD); + fails |= test_wrp (EBADF, write, -1, "Hello", sizeof ("Hello") ); + fails |= test_wrp (EBADF, writev, -1, iov, 1 ); + + return fails; +} + +#include "support/test-driver.c" diff --git a/REORG.TODO/posix/test-vfork.c b/REORG.TODO/posix/test-vfork.c new file mode 100644 index 0000000000..6dfb7d47e3 --- /dev/null +++ b/REORG.TODO/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 (void) +{ +} diff --git a/REORG.TODO/posix/testcases.h b/REORG.TODO/posix/testcases.h new file mode 100644 index 0000000000..834f53049f --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/testfnm.c b/REORG.TODO/posix/testfnm.c new file mode 100644 index 0000000000..7a04d2a912 --- /dev/null +++ b/REORG.TODO/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, 0 }, + { "[/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/REORG.TODO/posix/times.c b/REORG.TODO/posix/times.c new file mode 100644 index 0000000000..cd55da672b --- /dev/null +++ b/REORG.TODO/posix/times.c @@ -0,0 +1,40 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (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) diff --git a/REORG.TODO/posix/transbug.c b/REORG.TODO/posix/transbug.c new file mode 100644 index 0000000000..d0983b4d44 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-boost.c b/REORG.TODO/posix/tst-boost.c new file mode 100644 index 0000000000..75fba8dc2e --- /dev/null +++ b/REORG.TODO/posix/tst-boost.c @@ -0,0 +1,226 @@ +/* Regular expression tests. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-chmod.c b/REORG.TODO/posix/tst-chmod.c new file mode 100644 index 0000000000..ca222f5fa0 --- /dev/null +++ b/REORG.TODO/posix/tst-chmod.c @@ -0,0 +1,377 @@ +/* Test for chmod functions. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-cpucount.c b/REORG.TODO/posix/tst-cpucount.c new file mode 100644 index 0000000000..b3691a18da --- /dev/null +++ b/REORG.TODO/posix/tst-cpucount.c @@ -0,0 +1,28 @@ +#include <sched.h> +#include <stdio.h> +#include <sys/param.h> + +static int +do_test (void) +{ + cpu_set_t c; + + CPU_ZERO (&c); + + for (int cnt = 0; cnt < MIN (CPU_SETSIZE, 130); ++cnt) + { + int n = CPU_COUNT (&c); + if (n != cnt) + { + printf ("expected %d, not %d\n", cnt, n); + return 1; + } + + CPU_SET (cnt, &c); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-cpuset.c b/REORG.TODO/posix/tst-cpuset.c new file mode 100644 index 0000000000..d736793222 --- /dev/null +++ b/REORG.TODO/posix/tst-cpuset.c @@ -0,0 +1,82 @@ +#include <sched.h> +#include <stdio.h> + +static int +do_test (void) +{ + int result = 0; + + cpu_set_t s1; + cpu_set_t s2; + cpu_set_t s3; + + CPU_ZERO (&s1); + CPU_SET (0, &s1); + + CPU_ZERO (&s2); + CPU_SET (0, &s2); + CPU_SET (1, &s2); + + CPU_AND (&s3, &s1, &s2); + if (! CPU_EQUAL (&s3, &s1)) + { + puts ("result of CPU_AND wrong"); + result = 1; + } + + CPU_OR (&s3, &s1, &s2); + if (! CPU_EQUAL (&s3, &s2)) + { + puts ("result of CPU_OR wrong"); + result = 1; + } + + CPU_XOR (&s3, &s1, &s2); + if (CPU_COUNT (&s3) != 1) + { + puts ("result of CPU_XOR wrong"); + result = 1; + } + + cpu_set_t *vs1 = CPU_ALLOC (2048); + cpu_set_t *vs2 = CPU_ALLOC (2048); + cpu_set_t *vs3 = CPU_ALLOC (2048); + size_t vssize = CPU_ALLOC_SIZE (2048); + + CPU_ZERO_S (vssize, vs1); + CPU_SET_S (0, vssize, vs1); + + CPU_ZERO_S (vssize, vs2); + CPU_SET_S (0, vssize, vs2); + CPU_SET_S (2047, vssize, vs2); + + CPU_AND_S (vssize, vs3, vs1, vs2); + if (! CPU_EQUAL_S (vssize, vs3, vs1)) + { + puts ("result of CPU_AND_S wrong"); + result = 1; + } + + CPU_OR_S (vssize, vs3, vs1, vs2); + if (! CPU_EQUAL_S (vssize, vs3, vs2)) + { + puts ("result of CPU_OR_S wrong"); + result = 1; + } + + CPU_XOR_S (vssize, vs3, vs1, vs2); + if (CPU_COUNT_S (vssize, vs3) != 1) + { + puts ("result of CPU_XOR_S wrong"); + result = 1; + } + + CPU_FREE (vs1); + CPU_FREE (vs2); + CPU_FREE (vs3); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-dir.c b/REORG.TODO/posix/tst-dir.c new file mode 100644 index 0000000000..fee79b32a0 --- /dev/null +++ b/REORG.TODO/posix/tst-dir.c @@ -0,0 +1,582 @@ +/* Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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> +#include <libc-diag.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); + } + + /* The test below covers the deprecated readdir64_r function. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); + + /* 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; + } + } + + DIAG_POP_NEEDS_COMMENT; + + 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; + } + + /* The test below covers the deprecated readdir64_r function. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); + + /* 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; + } + } + + DIAG_POP_NEEDS_COMMENT; + + 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/REORG.TODO/posix/tst-exec-static.c b/REORG.TODO/posix/tst-exec-static.c new file mode 100644 index 0000000000..bdd636995a --- /dev/null +++ b/REORG.TODO/posix/tst-exec-static.c @@ -0,0 +1 @@ +#include "tst-exec.c" diff --git a/REORG.TODO/posix/tst-exec.c b/REORG.TODO/posix/tst-exec.c new file mode 100644 index 0000000000..12a0f57114 --- /dev/null +++ b/REORG.TODO/posix/tst-exec.c @@ -0,0 +1,199 @@ +/* Tests for exec. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + +/* File descriptors for these temporary files. */ +static int temp_fd1 = -1; +static int temp_fd2 = -1; + +/* 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[]) +{ + /* We must not open any files in the restart case. */ + if (restart) + return; + + temp_fd1 = create_temp_file ("exec", &name1); + temp_fd2 = create_temp_file ("exec", &name2); + if (temp_fd1 < 0 || temp_fd2 < 0) + exit (1); +} + + +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 flags; + int status; + + /* We must have + - one or four parameters left if called initially + + path for ld.so optional + + "--library-path" optional + + the library path optional + + 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 != 2 && 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. */ + + /* Set the bit. */ + flags = fcntl (temp_fd1, F_GETFD, 0); + if (flags < 0) + error (EXIT_FAILURE, errno, "cannot get flags"); + flags |= FD_CLOEXEC; + if (fcntl (temp_fd1, F_SETFD, flags) < 0) + error (EXIT_FAILURE, errno, "cannot set flags"); + + /* Write something in the files. */ + if (write (temp_fd1, fd1string, strlen (fd1string)) != strlen (fd1string)) + error (EXIT_FAILURE, errno, "cannot write to first file"); + if (write (temp_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", temp_fd1); + snprintf (fd2name, sizeof fd2name, "%d", temp_fd2); + + /* This is the child. Construct the command line. */ + if (argc == 5) + execl (argv[1], argv[1], argv[2], argv[3], argv[4], "--direct", + "--restart", fd1name, fd2name, name1, NULL); + else + execl (argv[1], argv[1], "--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); + + return status; +} diff --git a/REORG.TODO/posix/tst-execl1.c b/REORG.TODO/posix/tst-execl1.c new file mode 100644 index 0000000000..1cfa36df12 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execl2.c b/REORG.TODO/posix/tst-execl2.c new file mode 100644 index 0000000000..5b74959ef8 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execle1.c b/REORG.TODO/posix/tst-execle1.c new file mode 100644 index 0000000000..84470703f1 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execle2.c b/REORG.TODO/posix/tst-execle2.c new file mode 100644 index 0000000000..0430b7b573 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execlp1.c b/REORG.TODO/posix/tst-execlp1.c new file mode 100644 index 0000000000..1be4dbcb1b --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execlp2.c b/REORG.TODO/posix/tst-execlp2.c new file mode 100644 index 0000000000..81a723dda4 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execv1.c b/REORG.TODO/posix/tst-execv1.c new file mode 100644 index 0000000000..57ed1add6e --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execv2.c b/REORG.TODO/posix/tst-execv2.c new file mode 100644 index 0000000000..a5168a269c --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execve1.c b/REORG.TODO/posix/tst-execve1.c new file mode 100644 index 0000000000..356610f635 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execve2.c b/REORG.TODO/posix/tst-execve2.c new file mode 100644 index 0000000000..1a804e94fd --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-execvp1.c b/REORG.TODO/posix/tst-execvp1.c new file mode 100644 index 0000000000..8b718485d0 --- /dev/null +++ b/REORG.TODO/posix/tst-execvp1.c @@ -0,0 +1,38 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifndef EXECVP +# define EXECVP(file, argv) execvp (file, argv) +#endif + +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/REORG.TODO/posix/tst-execvp2.c b/REORG.TODO/posix/tst-execvp2.c new file mode 100644 index 0000000000..440dfab438 --- /dev/null +++ b/REORG.TODO/posix/tst-execvp2.c @@ -0,0 +1,85 @@ +#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" + +#ifndef EXECVP +# define EXECVP(file, argv) execvp (file, argv) +#endif + +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/REORG.TODO/posix/tst-execvp3.c b/REORG.TODO/posix/tst-execvp3.c new file mode 100644 index 0000000000..02a937c2da --- /dev/null +++ b/REORG.TODO/posix/tst-execvp3.c @@ -0,0 +1,45 @@ +#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" + +#ifndef EXECVP +# define EXECVP(file, argv) execvp (file, argv) +#endif + +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/REORG.TODO/posix/tst-execvp4.c b/REORG.TODO/posix/tst-execvp4.c new file mode 100644 index 0000000000..589a56018f --- /dev/null +++ b/REORG.TODO/posix/tst-execvp4.c @@ -0,0 +1,39 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#ifndef EXECVP +# define EXECVP(file, argv) execvp (file, argv) +#endif + +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/REORG.TODO/posix/tst-execvpe1.c b/REORG.TODO/posix/tst-execvpe1.c new file mode 100644 index 0000000000..b57b1e841b --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe1.c @@ -0,0 +1,20 @@ +/* Check ENOENT failure for execvpe. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define EXECVP(file, argv) execvpe (file, argv, NULL) +#include <posix/tst-execvp1.c> diff --git a/REORG.TODO/posix/tst-execvpe2.c b/REORG.TODO/posix/tst-execvpe2.c new file mode 100644 index 0000000000..4256f62fa2 --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe2.c @@ -0,0 +1,20 @@ +/* Check EACCES for execvpe. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define EXECVP(file, argv) execvpe (file, argv, NULL) +#include <posix/tst-execvp2.c> diff --git a/REORG.TODO/posix/tst-execvpe3.c b/REORG.TODO/posix/tst-execvpe3.c new file mode 100644 index 0000000000..03fa52186b --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe3.c @@ -0,0 +1,20 @@ +/* Check script execution without shebang for execvpe. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define EXECVP(file, argv) execvpe (file, argv, NULL) +#include <posix/tst-execvp3.c> diff --git a/REORG.TODO/posix/tst-execvpe4.c b/REORG.TODO/posix/tst-execvpe4.c new file mode 100644 index 0000000000..28236f6525 --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe4.c @@ -0,0 +1,20 @@ +/* Check unexistent binary for execvpe. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define EXECVP(file, argv) execvpe (file, argv, NULL) +#include <posix/tst-execvp4.c> diff --git a/REORG.TODO/posix/tst-execvpe5.c b/REORG.TODO/posix/tst-execvpe5.c new file mode 100644 index 0000000000..d91d92997a --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe5.c @@ -0,0 +1,160 @@ +/* General tests for execpve. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.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[]); + +#include "../test-skeleton.c" + +#define EXECVPE_KEY "EXECVPE_ENV" +#define EXECVPE_VALUE "execvpe_test" + + +static int +handle_restart (void) +{ + /* First check if only one variable is passed on execvpe. */ + int env_count = 0; + for (char **e = environ; *e != NULL; ++e) + if (++env_count == INT_MAX) + { + printf ("Environment variable number overflow"); + exit (EXIT_FAILURE); + } + if (env_count != 1) + { + printf ("Wrong number of environment variables"); + exit (EXIT_FAILURE); + } + + /* Check if the combinarion os "EXECVPE_ENV=execvpe_test" */ + const char *env = getenv (EXECVPE_KEY); + if (env == NULL) + { + printf ("Test environment variable not found"); + exit (EXIT_FAILURE); + } + + if (strncmp (env, EXECVPE_VALUE, sizeof (EXECVPE_VALUE))) + { + printf ("Test environment variable with wrong value"); + exit (EXIT_FAILURE); + } + + return 0; +} + + +int +do_test (int argc, char *argv[]) +{ + pid_t pid; + int status; + + /* We must have + - one or four parameters left if called initially + + path for ld.so optional + + "--library-path" optional + + the library path optional + + the application name + + if --enable-hardcoded-path-in-tests is used, just + + the application name + */ + + if (restart) + { + if (argc != 1) + { + printf ("Wrong number of arguments (%d) in restart\n", argc); + exit (EXIT_FAILURE); + } + + return handle_restart (); + } + + if (argc != 2 && argc != 5) + { + printf ("Wrong number of arguments (%d)\n", argc); + exit (EXIT_FAILURE); + } + + /* We want to test the `execvpe' function. To do this we restart the + program with an additional parameter. */ + pid = fork (); + if (pid == 0) + { + /* This is the child. Construct the command line. */ + + /* We cast here to char* because the test itself does not modify neither + the argument nor the environment list. */ + char *envs[] = { (char*)(EXECVPE_KEY "=" EXECVPE_VALUE), NULL }; + if (argc == 5) + { + char *args[] = { argv[1], argv[2], argv[3], argv[4], + (char *) "--direct", (char *) "--restart", NULL }; + execvpe (args[0], args, envs); + } + else + { + char *args[] = { argv[0], + (char *) "--direct", (char *) "--restart", NULL }; + execvpe (args[0], args, envs); + } + + puts ("Cannot exec"); + exit (EXIT_FAILURE); + } + else if (pid == (pid_t) -1) + { + puts ("Cannot fork"); + return 1; + } + + /* Wait for the child. */ + if (waitpid (pid, &status, 0) != pid) + { + puts ("Wrong child"); + return 1; + } + + if (WTERMSIG (status) != 0) + { + puts ("Child terminated incorrectly"); + return 1; + } + status = WEXITSTATUS (status); + + return status; +} diff --git a/REORG.TODO/posix/tst-execvpe6.c b/REORG.TODO/posix/tst-execvpe6.c new file mode 100644 index 0000000000..0636834ead --- /dev/null +++ b/REORG.TODO/posix/tst-execvpe6.c @@ -0,0 +1,150 @@ +/* Check execvpe script argument handling. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/param.h> + +static char *fname1; +static char *fname2; +static char *logname; + +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 void +do_prepare (void) +{ + int logfd = create_temp_file ("logfile", &logname); + close (logfd); + + int fd1 = create_temp_file ("testscript", &fname1); + dprintf (fd1, "echo foo $1 $2 $3 > %s\n", logname); + fchmod (fd1, 0700); + close (fd1); + + int fd2 = create_temp_file ("testscript", &fname2); + dprintf (fd2, "echo foo > %s\n", logname); + fchmod (fd2, 0700); + close (fd2); +} + +static int +run_script (const char *fname, char *args[]) +{ + /* We want to test the `execvpe' function. To do this we restart the + program with an additional parameter. */ + int status; + pid_t pid = fork (); + if (pid == 0) + { + execvpe (fname, args, NULL); + + puts ("Cannot exec"); + exit (EXIT_FAILURE); + } + else if (pid == (pid_t) -1) + { + puts ("Cannot fork"); + return 1; + } + + /* Wait for the child. */ + if (waitpid (pid, &status, 0) != pid) + { + puts ("Wrong child"); + return 1; + } + + if (WTERMSIG (status) != 0) + { + puts ("Child terminated incorrectly"); + return 1; + } + + return 0; +} + +static int +check_output (const char *expected) +{ + /* Check log output. */ + FILE *arq = fopen (logname, "r"); + if (arq == NULL) + { + puts ("Error opening output file"); + return 1; + } + + char line[128]; + if (fgets (line, sizeof (line), arq) == NULL) + { + puts ("Error reading output file"); + return 1; + } + fclose (arq); + + if (strcmp (line, expected) != 0) + { + puts ("Output file different than expected"); + return 1; + } + + return 0; +} + +static int +do_test (void) +{ + if (setenv ("PATH", test_dir, 1) != 0) + { + puts ("setenv failed"); + return 1; + } + + /* First check resulting script run with some arguments results in correct + output file. */ + char *args1[] = { fname1, (char*) "1", (char *) "2", (char *) "3", NULL }; + if (run_script (fname1,args1)) + return 1; + if (check_output ("foo 1 2 3\n")) + return 1; + + /* Same as before but with an expected empty argument list. */ + char *args2[] = { fname2, NULL }; + if (run_script (fname2, args2)) + return 1; + if (check_output ("foo\n")) + return 1; + + /* Same as before but with an empty argument list. */ + char *args3[] = { NULL }; + if (run_script (fname2, args3)) + return 1; + if (check_output ("foo\n")) + return 1; + + return 0; +} diff --git a/REORG.TODO/posix/tst-fnmatch.c b/REORG.TODO/posix/tst-fnmatch.c new file mode 100644 index 0000000000..02ec84b9b3 --- /dev/null +++ b/REORG.TODO/posix/tst-fnmatch.c @@ -0,0 +1,393 @@ +/* Tests for fnmatch function. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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> +#include <mcheck.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); + + +static int +do_test (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; + + mtrace (); + + /* 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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-fnmatch.input b/REORG.TODO/posix/tst-fnmatch.input new file mode 100644 index 0000000000..d1621e8b08 --- /dev/null +++ b/REORG.TODO/posix/tst-fnmatch.input @@ -0,0 +1,755 @@ +# Tests for fnmatch. +# Copyright (C) 2000-2017 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, see +# <http://www.gnu.org/licenses/>. + + +# 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 "/[" "\\/[" 0 +C "/[]" "\\/\\[]" 0 + +# 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/REORG.TODO/posix/tst-fnmatch2.c b/REORG.TODO/posix/tst-fnmatch2.c new file mode 100644 index 0000000000..e66a01f592 --- /dev/null +++ b/REORG.TODO/posix/tst-fnmatch2.c @@ -0,0 +1,40 @@ +#include <fnmatch.h> +#include <stdio.h> + +int +do_test (void) +{ + char pattern[] = "a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*"; + const char *string = "aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmm" + "nnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyy"; + if (fnmatch (pattern, string, 0) != FNM_NOMATCH) + { + puts ("First fnmatch didn't return FNM_NOMATCH"); + return 1; + } + pattern[(sizeof pattern) - 3] = '*'; + if (fnmatch (pattern, string, 0) != 0) + { + puts ("Second fnmatch didn't return 0"); + return 1; + } + if (fnmatch ("a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD) != FNM_NOMATCH) + { + puts ("Third fnmatch didn't return FNM_NOMATCH"); + return 1; + } + if (fnmatch ("a*b/*", "abbb/xy", FNM_PATHNAME | FNM_PERIOD) != 0) + { + puts ("Fourth fnmatch didn't return 0"); + return 1; + } + if (fnmatch ("[", "[", 0) != 0) + { + puts ("Fifth fnmatch didn't return 0"); + return 1; + } + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-fnmatch3.c b/REORG.TODO/posix/tst-fnmatch3.c new file mode 100644 index 0000000000..c6f3a1fc18 --- /dev/null +++ b/REORG.TODO/posix/tst-fnmatch3.c @@ -0,0 +1,52 @@ +/* Test for fnmatch not reading past the end of the pattern. + Copyright (C) 2014-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <fnmatch.h> +#include <sys/mman.h> +#include <string.h> +#include <unistd.h> + +int +do_bz18036 (void) +{ + const char p[] = "**(!()"; + const int pagesize = getpagesize (); + + char *pattern = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (pattern == MAP_FAILED) return 1; + + mprotect (pattern + pagesize, pagesize, PROT_NONE); + memset (pattern, ' ', pagesize); + strcpy (pattern, p); + + return fnmatch (pattern, p, FNM_EXTMATCH); +} + +int +do_test (void) +{ + if (fnmatch ("[[:alpha:]'[:alpha:]\0]", "a", 0) != FNM_NOMATCH) + return 1; + if (fnmatch ("[a[.\0.]]", "a", 0) != FNM_NOMATCH) + return 1; + return do_bz18036 (); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-fork.c b/REORG.TODO/posix/tst-fork.c new file mode 100644 index 0000000000..fba82631ce --- /dev/null +++ b/REORG.TODO/posix/tst-fork.c @@ -0,0 +1,151 @@ +/* Tests for fork. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-getaddrinfo.c b/REORG.TODO/posix/tst-getaddrinfo.c new file mode 100644 index 0000000000..b5ea201cdb --- /dev/null +++ b/REORG.TODO/posix/tst-getaddrinfo.c @@ -0,0 +1,68 @@ +/* Copyright (C) 1999-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-getaddrinfo2.c b/REORG.TODO/posix/tst-getaddrinfo2.c new file mode 100644 index 0000000000..d8be4a8e8f --- /dev/null +++ b/REORG.TODO/posix/tst-getaddrinfo2.c @@ -0,0 +1,78 @@ +/* Test by David L Stevens <dlstevens@us.ibm.com> [BZ #358] */ +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <stdio.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/REORG.TODO/posix/tst-getaddrinfo3.c b/REORG.TODO/posix/tst-getaddrinfo3.c new file mode 100644 index 0000000000..5077f311fc --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-getaddrinfo4.c b/REORG.TODO/posix/tst-getaddrinfo4.c new file mode 100644 index 0000000000..0b6d79a36e --- /dev/null +++ b/REORG.TODO/posix/tst-getaddrinfo4.c @@ -0,0 +1,68 @@ +/* Test getaddrinfo return value, [BZ #15339]. + Copyright (C) 2013-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <netdb.h> + +static int +try (const char *service, int family, int flags) +{ + struct addrinfo hints, *h, *ai; + int res; + + memset (&hints, 0, sizeof hints); + hints.ai_family = family; + hints.ai_flags = flags; + + errno = 0; + h = (family || flags) ? &hints : NULL; + res = getaddrinfo ("example.net", service, h, &ai); + switch (res) + { + case 0: + case EAI_AGAIN: + case EAI_NONAME: + printf ("SUCCESS getaddrinfo(service=%s, family=%d, flags=%d): %s: %m\n", + service ?: "NULL", family, flags, gai_strerror (res)); + return 0; + } + printf ("FAIL getaddrinfo(service=%s, family=%d, flags=%d): %s: %m\n", + service ?: "NULL", family, flags, gai_strerror (res)); + return 1; +} + +static int +do_test (void) +{ + int err = 0; + err |= try (NULL, 0, 0); + err |= try (NULL, AF_UNSPEC, AI_ADDRCONFIG); + err |= try (NULL, AF_INET, 0); + err |= try (NULL, AF_INET6, 0); + err |= try ("http", 0, 0); + err |= try ("http", AF_UNSPEC, AI_ADDRCONFIG); + err |= try ("http", AF_INET, 0); + err |= try ("http", AF_INET6, 0); + return err; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 10 +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-getaddrinfo5.c b/REORG.TODO/posix/tst-getaddrinfo5.c new file mode 100644 index 0000000000..acb1c29964 --- /dev/null +++ b/REORG.TODO/posix/tst-getaddrinfo5.c @@ -0,0 +1,70 @@ +/* Test host lookup with double dots at the end, [BZ #16469]. + Copyright (C) 2014-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +static int +test (void) +{ + static char host1[] = "localhost.."; + static char host2[] = "www.gnu.org.."; + static char *hosts[] = { host1, host2 }; + int i; + int pass = 0; + + for (i = 0; i < sizeof (hosts) / sizeof (*hosts); i++) + { + char *host = hosts[i]; + size_t len = strlen (host); + struct addrinfo *ai; + + /* If the name doesn't resolve with a single dot at the + end, skip it. */ + host[len-1] = 0; + if (getaddrinfo (host, NULL, NULL, &ai) != 0) + { + printf ("resolving \"%s\" failed, skipping this hostname\n", host); + continue; + } + printf ("resolving \"%s\" worked, proceeding to test\n", host); + freeaddrinfo (ai); + + /* If it resolved with a single dot, check that it doesn't with + a second trailing dot. */ + host[len-1] = '.'; + if (getaddrinfo (host, NULL, NULL, &ai) == 0) + { + printf ("resolving \"%s\" worked, test failed\n", host); + return 1; + } + printf ("resolving \"%s\" failed, test passed\n", host); + pass = 1; + } + + /* We want at least one successful name resolution for the test to + succeed. */ + return pass ? 0 : 2; +} + +#define TEST_FUNCTION test () +#define TIMEOUT 10 +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-getconf.sh b/REORG.TODO/posix/tst-getconf.sh new file mode 100644 index 0000000000..eead0419a6 --- /dev/null +++ b/REORG.TODO/posix/tst-getconf.sh @@ -0,0 +1,245 @@ +#!/bin/sh +# Test for getconf(1). +# Copyright (C) 2001-2017 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, see +# <http://www.gnu.org/licenses/>. + +set -e + +common_objpfx=$1; shift +run_getconf=$1; shift + +logfile=$common_objpfx/posix/tst-getconf.out + +rm -f $logfile +result=0 +while read name; do + printf %s "getconf $name: " >> $logfile + ${run_getconf} "$name" < /dev/null 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 + printf %s "getconf $name /: " >> $logfile + ${run_getconf} "$name" / < /dev/null 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/REORG.TODO/posix/tst-getopt-cancel.c b/REORG.TODO/posix/tst-getopt-cancel.c new file mode 100644 index 0000000000..594596a7b1 --- /dev/null +++ b/REORG.TODO/posix/tst-getopt-cancel.c @@ -0,0 +1,284 @@ +/* Copyright (C) 2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* fprintf is a cancellation point, but getopt is not supposed to be a + cancellation point, even when it prints error messages. */ + +/* Note: getopt.h must be included first in this file, so we get the + GNU getopt rather than the POSIX one. */ +#include <getopt.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include <fcntl.h> +#include <pthread.h> +#include <unistd.h> + +#include <support/support.h> +#include <support/temp_file.h> +#include <support/xthread.h> + +static bool +check_stderr (bool expect_errmsg, FILE *stderr_trapped) +{ + static char *lineptr = 0; + static size_t linesz = 0; + + bool got_errmsg = false; + rewind (stderr_trapped); + while (getline (&lineptr, &linesz, stderr_trapped) > 0) + { + got_errmsg = true; + fputs (lineptr, stdout); + } + rewind (stderr_trapped); + ftruncate (fileno (stderr_trapped), 0); + return got_errmsg == expect_errmsg; +} + +struct test_short +{ + const char *label; + const char *opts; + const char *const argv[8]; + int argc; + bool expect_errmsg; +}; + +struct test_long +{ + const char *label; + const char *opts; + const struct option longopts[4]; + const char *const argv[8]; + int argc; + bool expect_errmsg; +}; + +#define DEFINE_TEST_DRIVER(test_type, getopt_call) \ + struct test_type##_tdata \ + { \ + pthread_mutex_t *sync; \ + const struct test_type *tcase; \ + bool ok; \ + }; \ + \ + static void * \ + test_type##_threadproc (void *data) \ + { \ + struct test_type##_tdata *tdata = data; \ + const struct test_type *tc = tdata->tcase; \ + \ + xpthread_mutex_lock (tdata->sync); \ + xpthread_mutex_unlock (tdata->sync); \ + \ + /* At this point, this thread has a cancellation pending. \ + We should still be able to get all the way through a getopt \ + loop without being cancelled. \ + Setting optind to 0 forces getopt to reinitialize itself. */ \ + optind = 0; \ + opterr = 1; \ + optopt = 0; \ + while (getopt_call != -1) \ + ; \ + tdata->ok = true; \ + \ + pthread_testcancel(); \ + return 0; \ + } \ + \ + static bool \ + do_##test_type (const struct test_type *tcase, FILE *stderr_trapped) \ + { \ + pthread_mutex_t sync; \ + struct test_type##_tdata tdata; \ + \ + printf("begin: %s\n", tcase->label); \ + \ + xpthread_mutex_init (&sync, 0); \ + xpthread_mutex_lock (&sync); \ + \ + tdata.sync = &sync; \ + tdata.tcase = tcase; \ + tdata.ok = false; \ + \ + pthread_t thr = xpthread_create (0, test_type##_threadproc, \ + (void *)&tdata); \ + xpthread_cancel (thr); \ + xpthread_mutex_unlock (&sync); \ + void *rv = xpthread_join (thr); \ + \ + xpthread_mutex_destroy (&sync); \ + \ + bool ok = true; \ + if (!check_stderr (tcase->expect_errmsg, stderr_trapped)) \ + { \ + ok = false; \ + printf("FAIL: %s: stderr not as expected\n", tcase->label); \ + } \ + if (!tdata.ok) \ + { \ + ok = false; \ + printf("FAIL: %s: did not complete loop\n", tcase->label); \ + } \ + if (rv != PTHREAD_CANCELED) \ + { \ + ok = false; \ + printf("FAIL: %s: thread was not cancelled\n", tcase->label); \ + } \ + if (ok) \ + printf ("pass: %s\n", tcase->label); \ + return ok; \ + } + +DEFINE_TEST_DRIVER (test_short, + getopt (tc->argc, (char *const *)tc->argv, tc->opts)) +DEFINE_TEST_DRIVER (test_long, + getopt_long (tc->argc, (char *const *)tc->argv, + tc->opts, tc->longopts, 0)) + +/* Caution: all option strings must begin with a '+' or '-' so that + getopt does not attempt to permute the argument vector (which is in + read-only memory). */ +const struct test_short tests_short[] = { + { "no errors", + "+ab:c", { "program", "-ac", "-b", "x", 0 }, 4, false }, + { "invalid option", + "+ab:c", { "program", "-d", 0 }, 2, true }, + { "missing argument", + "+ab:c", { "program", "-b", 0 }, 2, true }, + { 0 } +}; + +const struct test_long tests_long[] = { + { "no errors (long)", + "+ab:c", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "--charlie", "--bravo=x", 0 }, 4, false }, + + { "invalid option (long)", + "+ab:c", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "--charlie", "--dingo", 0 }, 4, true }, + + { "unwanted argument", + "+ab:c", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "--charlie=dingo", "--bravo=x", 0 }, 4, true }, + + { "missing argument", + "+ab:c", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "--charlie", "--bravo", 0 }, 4, true }, + + { "ambiguous options", + "+uvw", { { "veni", no_argument, 0, 'u' }, + { "vedi", no_argument, 0, 'v' }, + { "veci", no_argument, 0, 'w' } }, + { "program", "--ve", 0 }, 2, true }, + + { "no errors (long W)", + "+ab:cW;", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "-W", "charlie", "-W", "bravo=x", 0 }, 6, false }, + + { "missing argument (W itself)", + "+ab:cW;", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "-W", "charlie", "-W", 0 }, 5, true }, + + { "missing argument (W longopt)", + "+ab:cW;", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "-W", "charlie", "-W", "bravo", 0 }, 6, true }, + + { "unwanted argument (W longopt)", + "+ab:cW;", { { "alpha", no_argument, 0, 'a' }, + { "bravo", required_argument, 0, 'b' }, + { "charlie", no_argument, 0, 'c' }, + { 0 } }, + { "program", "-a", "-W", "charlie=dingo", "-W", "bravo=x", 0 }, 6, true }, + + { "ambiguous options (W)", + "+uvwW;", { { "veni", no_argument, 0, 'u' }, + { "vedi", no_argument, 0, 'v' }, + { "veci", no_argument, 0, 'w' } }, + { "program", "-W", "ve", 0 }, 3, true }, + + { 0 } +}; + +static int +do_test (void) +{ + int stderr_trap = create_temp_file ("stderr", 0); + if (stderr_trap < 0) + { + perror ("create_temp_file"); + return 1; + } + FILE *stderr_trapped = fdopen(stderr_trap, "r+"); + if (!stderr_trapped) + { + perror ("fdopen"); + return 1; + } + int old_stderr = dup (fileno (stderr)); + if (old_stderr < 0) + { + perror ("dup"); + return 1; + } + if (dup2 (stderr_trap, 2) < 0) + { + perror ("dup2"); + return 1; + } + rewind (stderr); + + bool success = true; + + for (const struct test_short *tcase = tests_short; tcase->label; tcase++) + success = do_test_short (tcase, stderr_trapped) && success; + + for (const struct test_long *tcase = tests_long; tcase->label; tcase++) + success = do_test_long (tcase, stderr_trapped) && success; + + dup2 (old_stderr, 2); + close (old_stderr); + fclose (stderr_trapped); + + return success ? 0 : 1; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/posix/tst-getopt_long1.c b/REORG.TODO/posix/tst-getopt_long1.c new file mode 100644 index 0000000000..6d8ef02ca4 --- /dev/null +++ b/REORG.TODO/posix/tst-getopt_long1.c @@ -0,0 +1,62 @@ +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) +{ + if (create_temp_file ("tst-getopt_long1", &fname) < 0) + { + printf ("cannot create temp file: %m\n"); + exit (1); + } +} + + +static const struct option opts[] = + { + { "one", no_argument, NULL, '1' }, + { "two", no_argument, NULL, '2' }, + { "one-one", no_argument, NULL, '3' }, + { "four", no_argument, NULL, '4' }, + { "onto", no_argument, NULL, '5' }, + { NULL, 0, NULL, 0 } + }; + + +static int +do_test (void) +{ + if (freopen (fname, "w+", stderr) == NULL) + { + printf ("freopen failed: %m\n"); + return 1; + } + + char *argv[] = { (char *) "program", (char *) "--on" }; + int argc = 2; + + int c = getopt_long (argc, argv, "12345", opts, NULL); + printf ("return value: %c\n", c); + + rewind (stderr); + char *line = NULL; + size_t len = 0; + if (getline (&line, &len, stderr) < 0) + { + printf ("cannot read stderr redirect: %m\n"); + return 1; + } + printf ("message = \"%s\"\n", line); + + static const char expected[] = "\ +program: option '--on' is ambiguous; possibilities: '--one' '--one-one' '--onto'\n"; + + return c != '?' || strcmp (line, expected) != 0; +} diff --git a/REORG.TODO/posix/tst-gnuglob.c b/REORG.TODO/posix/tst-gnuglob.c new file mode 100644 index 0000000000..d753674c5f --- /dev/null +++ b/REORG.TODO/posix/tst-gnuglob.c @@ -0,0 +1,502 @@ +/* Test the GNU extensions in glob which allow the user to provide callbacks + for the filesystem access functions. + Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + + while (s[0] == '/') + { + if (s[1] == '\0') + { + s = "."; + break; + } + ++s; + } + + 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 || filesystem[idx].type != DT_DIR) + { + 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 = 1; /* glob should not skip this entry. */ + +#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) +{ + static const char *const 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; +#undef nstrs +} + + +static const char * +errstr (int val) +{ + static const char *const strs[] = + { + [GLOB_NOSPACE] = "GLOB_NOSPACE", + [GLOB_ABORTED] = "GLOB_ABORTED", + [GLOB_NOMATCH] = "GLOB_NOMATCH", + [GLOB_NOSYS] = "GLOB_NOSYS" + }; +#define nstrs (sizeof (strs) / sizeof (strs[0])) + static char buf[100]; + if (val < 0 || val >= nstrs || strs[val] == NULL) + { + snprintf (buf, sizeof (buf), "GLOB_??? (%d)", val); + return buf; + } + return strs[val]; +#undef nstrs +} + + +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; +} + + +static int +do_test (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, r, c...) \ + fmt = a; \ + flags = GLOB_ALTDIRFUNC | b; \ + errval = glob (fmt, flags, NULL, &gl); \ + if (errval != r) \ + { \ + if (r == 0) \ + printf ("glob (\"%s\", %s) failed: %s\n", fmt, flagstr (flags), \ + errval >= 0 && errval < nglob_errstring \ + ? glob_errstring[errval] : "???"); \ + else \ + printf ("glob (\"%s\", %s) did not fail\n", fmt, flagstr (flags)); \ + result = 1; \ + } \ + else if (r == 0) \ + result |= test_result (fmt, flags, &gl, (const char *[]) { c, NULL }); \ + else \ + printf ("result for glob (\"%s\", %s) = %s\n\n", fmt, flagstr (flags), \ + errstr (errval)) + + test ("*/*/*", 0, 0, + "dir1lev1/dir2lev2/dir1lev3", + "dir1lev1/dir2lev2/file1lev3", + "dir1lev1/dir2lev2/file2lev3", + "dir1lev1/dir3lev2/file3lev3", + "dir1lev1/dir3lev2/file4lev3"); + + test ("*/*/*", GLOB_PERIOD, 0, + "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 ("*/*/.*", 0, 0, + "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*/.*", 0, 0, + "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*/.*", 0, 0, + "dir1lev1/dir1lev2/.", + "dir1lev1/dir1lev2/..", + "dir2lev1/dir1lev2/.", + "dir2lev1/dir1lev2/..", + "dir2lev1/dir1lev2/.dir", + "dir2lev1/dir1lev2/.foo"); + + test ("\\/*", 0, 0, + "/dir1lev1", + "/dir2lev1", + "/file1lev1", + "/file2lev1"); + + test ("*/*/", 0 , 0, + "dir1lev1/dir1lev2/", + "dir1lev1/dir2lev2/", + "dir1lev1/dir3lev2/", + "dir2lev1/dir1lev2/"); + + test ("", 0, GLOB_NOMATCH, NULL); + + test ("", GLOB_NOCHECK, 0, ""); + + globfree (&gl); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-mmap-offset.c b/REORG.TODO/posix/tst-mmap-offset.c new file mode 100644 index 0000000000..5bb88aab10 --- /dev/null +++ b/REORG.TODO/posix/tst-mmap-offset.c @@ -0,0 +1,118 @@ +/* BZ #18877 and #21270 mmap offset test. + + Copyright (C) 2015-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> + +#include <support/check.h> + +static int fd; +static long int page_shift; +static char fname[] = "tst-mmap-offset-XXXXXX"; + +static void +do_prepare (int argc, char **argv) +{ + fd = mkstemp64 (fname); + if (fd < 0) + FAIL_EXIT1 ("mkstemp failed"); + + if (unlink (fname)) + FAIL_EXIT1 ("unlink failed"); + + long sz = sysconf(_SC_PAGESIZE); + if (sz == -1) + sz = 4096L; + page_shift = ffs (sz) - 1; +} + +#define PREPARE do_prepare + + +/* Check if negative offsets are handled correctly by mmap. */ +static int +do_test_bz18877 (void) +{ + const int prot = PROT_READ | PROT_WRITE; + const int flags = MAP_SHARED; + const unsigned long length = 0x10000; + const unsigned long offset = 0xace00000; + const unsigned long size = offset + length; + void *addr; + + if (ftruncate64 (fd, size)) + FAIL_RET ("ftruncate64 failed"); + + addr = mmap (NULL, length, prot, flags, fd, offset); + if (MAP_FAILED == addr) + FAIL_RET ("mmap failed"); + + /* This memcpy is likely to SIGBUS if mmap has messed up with offset. */ + memcpy (addr, fname, sizeof (fname)); + + return 0; +} + +/* Check if invalid offset are handled correctly by mmap. */ +static int +do_test_bz21270 (void) +{ + /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is + implemented with __SYS_mmap2 syscall and the offset is represented in + multiples of page size. For offset larger than + '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with + page size of 4096 bytes) the system call silently truncates the offset. + For this case glibc mmap implementation returns EINVAL. */ + const int prot = PROT_READ | PROT_WRITE; + const int flags = MAP_SHARED; + const int64_t offset = 1ULL << (page_shift + 8 * sizeof (uint32_t)); + const size_t length = 4096; + + void *addr = mmap64 (NULL, length, prot, flags, fd, offset); + if (sizeof (off_t) < sizeof (off64_t)) + { + if ((addr != MAP_FAILED) && (errno != EINVAL)) + FAIL_RET ("mmap succeed"); + } + else + { + if (addr == MAP_FAILED) + FAIL_RET ("mmap failed"); + } + + return 0; +} + +int +do_test (void) +{ + int ret = 0; + + ret += do_test_bz18877 (); + ret += do_test_bz21270 (); + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/posix/tst-mmap.c b/REORG.TODO/posix/tst-mmap.c new file mode 100644 index 0000000000..5e52b49e35 --- /dev/null +++ b/REORG.TODO/posix/tst-mmap.c @@ -0,0 +1,200 @@ +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> + + +static int +do_test (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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-nanosleep.c b/REORG.TODO/posix/tst-nanosleep.c new file mode 100644 index 0000000000..d1444aec55 --- /dev/null +++ b/REORG.TODO/posix/tst-nanosleep.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-nice.c b/REORG.TODO/posix/tst-nice.c new file mode 100644 index 0000000000..93416f82a6 --- /dev/null +++ b/REORG.TODO/posix/tst-nice.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + } + + /* BZ #18086. Make sure we don't reset errno. */ + errno = EBADF; + nice (0); + if (errno != EBADF) + { + printf ("FAIL: errno = %i, but wanted EBADF (%i)\n", errno, EBADF); + 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/REORG.TODO/posix/tst-pathconf.c b/REORG.TODO/posix/tst-pathconf.c new file mode 100644 index 0000000000..88df792ab3 --- /dev/null +++ b/REORG.TODO/posix/tst-pathconf.c @@ -0,0 +1,166 @@ +/* Test that values of pathconf and fpathconf are consistent for a file. + Copyright (C) 2013-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (void); +#define PREPARE(argc, argv) prepare () + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + +static int dir_fd; +static char *dirbuf; + +static void +prepare (void) +{ + size_t test_dir_len = strlen (test_dir); + static const char dir_name[] = "/tst-pathconf.XXXXXX"; + + size_t dirbuflen = test_dir_len + sizeof (dir_name); + dirbuf = xmalloc (dirbuflen); + + snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name); + if (mkdtemp (dirbuf) == NULL) + { + printf ("Cannot create temporary directory: %s\n", strerror (errno)); + exit (1); + } + + add_temp_file (dirbuf); + + dir_fd = open (dirbuf, O_RDONLY); + if (dir_fd == -1) + { + printf ("Cannot open directory: %s\n", strerror (errno)); + exit (1); + } +} + + +static int +do_test (void) +{ + int ret = 0; + static const char *fifo_name = "some-fifo"; + + size_t filenamelen = strlen (dirbuf) + strlen (fifo_name) + 2; + char *filename = xmalloc (filenamelen); + + snprintf (filename, filenamelen, "%s/%s", dirbuf, fifo_name); + + /* Create a fifo in the directory. */ + int e = mkfifo (filename, 0777); + if (e == -1) + { + printf ("fifo creation failed (%s)\n", strerror (errno)); + ret = 1; + goto out_nofifo; + } + + long dir_pathconf = pathconf (dirbuf, _PC_PIPE_BUF); + + if (dir_pathconf < 0) + { + printf ("pathconf on directory failed: %s\n", strerror (errno)); + ret = 1; + goto out_nofifo; + } + + long fifo_pathconf = pathconf (filename, _PC_PIPE_BUF); + + if (fifo_pathconf < 0) + { + printf ("pathconf on file failed: %s\n", strerror (errno)); + ret = 1; + goto out_nofifo; + } + + int fifo = open (filename, O_RDONLY | O_NONBLOCK); + + if (fifo < 0) + { + printf ("fifo open failed (%s)\n", strerror (errno)); + ret = 1; + goto out_nofifo; + } + + long dir_fpathconf = fpathconf (dir_fd, _PC_PIPE_BUF); + + if (dir_fpathconf < 0) + { + printf ("fpathconf on directory failed: %s\n", strerror (errno)); + ret = 1; + goto out; + } + + long fifo_fpathconf = fpathconf (fifo, _PC_PIPE_BUF); + + if (fifo_fpathconf < 0) + { + printf ("fpathconf on file failed: %s\n", strerror (errno)); + ret = 1; + goto out; + } + + if (fifo_pathconf != fifo_fpathconf) + { + printf ("fifo pathconf (%ld) != fifo fpathconf (%ld)\n", fifo_pathconf, + fifo_fpathconf); + ret = 1; + goto out; + } + + if (dir_pathconf != fifo_pathconf) + { + printf ("directory pathconf (%ld) != fifo pathconf (%ld)\n", + dir_pathconf, fifo_pathconf); + ret = 1; + goto out; + } + + if (dir_fpathconf != fifo_fpathconf) + { + printf ("directory fpathconf (%ld) != fifo fpathconf (%ld)\n", + dir_fpathconf, fifo_fpathconf); + ret = 1; + goto out; + } + +out: + close (fifo); +out_nofifo: + close (dir_fd); + + if (unlink (filename) != 0) + { + printf ("Could not remove fifo (%s)\n", strerror (errno)); + ret = 1; + } + + return ret; +} diff --git a/REORG.TODO/posix/tst-pcre.c b/REORG.TODO/posix/tst-pcre.c new file mode 100644 index 0000000000..2f10cf64ac --- /dev/null +++ b/REORG.TODO/posix/tst-pcre.c @@ -0,0 +1,240 @@ +/* Regular expression tests. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-posix_fadvise-common.c b/REORG.TODO/posix/tst-posix_fadvise-common.c new file mode 100644 index 0000000000..45e36fc56f --- /dev/null +++ b/REORG.TODO/posix/tst-posix_fadvise-common.c @@ -0,0 +1,111 @@ +/* Common posix_fadvise tests definitions. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <support/support.h> +#include <support/check.h> +#include <support/temp_file.h> + +static char *temp_filename; +static int temp_fd; +static char fifoname[] = "/tmp/tst-posix_fadvise-fifo-XXXXXX"; +static int fifofd; + +static void +do_prepare (int argc, char **argv) +{ + temp_fd = create_temp_file ("tst-posix_fadvise.", &temp_filename); + if (temp_fd == -1) + FAIL_EXIT1 ("cannot create temporary file: %m"); + + if (mktemp (fifoname) == NULL) + FAIL_EXIT1 ("cannot generate temp file name: %m"); + add_temp_file (fifoname); + + if (mkfifo (fifoname, S_IWUSR | S_IRUSR) != 0) + FAIL_EXIT1 ("cannot create fifo: %m"); + + fifofd = open (fifoname, O_RDONLY | O_NONBLOCK); + if (fifofd == -1) + FAIL_EXIT1 ("cannot open fifo: %m"); +} + +/* Effectivelly testing posix_fadvise is hard because side effects are not + observed without checking either performance or any kernel specific + supplied information. Also, the syscall is meant to be an advisory, + so the kernel is free to use this information in any way it deems fit, + including ignoring it. + + This test check for some invalid returned operation to check argument + passing and if implementation follows POSIX error definition. */ +static int +do_test_common (void) +{ + /* Add some data to file and ensure it is written to disk. */ +#define BLK_SIZE 2048 + char buffer[BLK_SIZE] = { 0xcd }; + ssize_t ret; + + if ((ret = write (temp_fd, buffer, BLK_SIZE)) != BLK_SIZE) + FAIL_EXIT1 ("write returned %zd different than expected %d", + ret, BLK_SIZE); + + if (fsync (temp_fd) != 0) + FAIL_EXIT1 ("fsync failed"); + + /* Test passing an invalid fd. */ + if (posix_fadvise (-1, 0, 0, POSIX_FADV_NORMAL) != EBADF) + FAIL_EXIT1 ("posix_fadvise with invalid fd did not return EBADF"); + + /* Test passing an invalid operation. */ + if (posix_fadvise (temp_fd, 0, 0, -1) != EINVAL) + FAIL_EXIT1 ("posix_fadvise with invalid advise did not return EINVAL"); + + /* Test passing a FIFO fd. */ + if (posix_fadvise (fifofd, 0, 0, POSIX_FADV_NORMAL) != ESPIPE) + FAIL_EXIT1 ("posix_advise with PIPE fd did not return ESPIPE"); + + /* Default fadvise on all file starting at initial position. */ + if (posix_fadvise (temp_fd, 0, 0, POSIX_FADV_NORMAL) != 0) + FAIL_EXIT1 ("default posix_fadvise failed"); + + if (posix_fadvise (temp_fd, 0, 2 * BLK_SIZE, POSIX_FADV_NORMAL) != 0) + FAIL_EXIT1 ("posix_fadvise failed (offset = 0, len = %d) failed", + BLK_SIZE); + + if (posix_fadvise (temp_fd, 2 * BLK_SIZE, 0, POSIX_FADV_NORMAL) != 0) + FAIL_EXIT1 ("posix_fadvise failed (offset = %d, len = 0) failed", + BLK_SIZE); + + return 0; +} + +#define PREPARE do_prepare + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include <support/test-driver.c> diff --git a/REORG.TODO/posix/tst-posix_fadvise.c b/REORG.TODO/posix/tst-posix_fadvise.c new file mode 100644 index 0000000000..896dbc2062 --- /dev/null +++ b/REORG.TODO/posix/tst-posix_fadvise.c @@ -0,0 +1,25 @@ +/* Basic posix_fadvise tests. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include "tst-posix_fadvise-common.c" + +static int +do_test (void) +{ + return do_test_common (); +} diff --git a/REORG.TODO/posix/tst-posix_fadvise64.c b/REORG.TODO/posix/tst-posix_fadvise64.c new file mode 100644 index 0000000000..d3ac35863a --- /dev/null +++ b/REORG.TODO/posix/tst-posix_fadvise64.c @@ -0,0 +1,46 @@ +/* Basic posix_fadvise64 tests. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define _FILE_OFFSET_BITS 64 +#include "tst-posix_fadvise-common.c" + +static int +do_test (void) +{ + int ret = do_test_common (); + if (ret == 1) + return 1; + + /* Test passing a negative length. The compat fadvise64 might use + off64_t for size argument passing, so using -1 for len without + _FILE_OFFSET_BITS might not trigger the length issue. */ + if (posix_fadvise (temp_fd, 0, -1, POSIX_FADV_NORMAL) != EINVAL) + FAIL_EXIT1 ("posix_fadvise with negative length did not return EINVAL"); + + /* Check with some offset values larger than 32-bits. */ + off_t offset = UINT32_MAX + 2048LL; + if (posix_fadvise (temp_fd, 0, offset, POSIX_FADV_NORMAL) != 0) + FAIL_EXIT1 ("posix_fadvise failed (offset = 0, len = %zd) failed", + (ssize_t)offset); + + if (posix_fadvise (temp_fd, offset, 0, POSIX_FADV_NORMAL) != 0) + FAIL_EXIT1 ("posix_fadvise failed (offset = %zd, len = 0) failed", + (ssize_t)offset); + + return 0; +} diff --git a/REORG.TODO/posix/tst-posix_spawn-fd.c b/REORG.TODO/posix/tst-posix_spawn-fd.c new file mode 100644 index 0000000000..4d5133ca81 --- /dev/null +++ b/REORG.TODO/posix/tst-posix_spawn-fd.c @@ -0,0 +1,165 @@ +/* Test that spawn file action functions work without file limit. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <spawn.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/resource.h> +#include <unistd.h> + +/* _SC_OPEN_MAX value. */ +static long maxfd; + +/* A positive but unused file descriptor, used for testing + purposes. */ +static int invalid_fd; + +/* Indicate that errors have been encountered. */ +static bool errors; + +static posix_spawn_file_actions_t actions; + +static void +one_test (const char *name, int (*func) (int), int fd, + bool expect_success) +{ + int ret = func (fd); + if (expect_success) + { + if (ret != 0) + { + errno = ret; + printf ("error: posix_spawn_file_actions_%s (%d): %m\n", name, fd); + errors = true; + } + } + else if (ret != EBADF) + { + if (ret == 0) + printf ("error: posix_spawn_file_actions_%s (%d):" + " unexpected success\n", name, fd); + else + { + errno = ret; + printf ("error: posix_spawn_file_actions_%s (%d): %m\n", name, fd); + } + errors = true; + } +} + +static void +all_tests (const char *name, int (*func) (int)) +{ + one_test (name, func, 0, true); + one_test (name, func, invalid_fd, true); + one_test (name, func, -1, false); + one_test (name, func, -2, false); + if (maxfd >= 0) + one_test (name, func, maxfd, false); +} + +static int +addopen (int fd) +{ + return posix_spawn_file_actions_addopen + (&actions, fd, "/dev/null", O_RDONLY, 0); +} + +static int +adddup2 (int fd) +{ + return posix_spawn_file_actions_adddup2 (&actions, fd, 1); +} + +static int +adddup2_reverse (int fd) +{ + return posix_spawn_file_actions_adddup2 (&actions, 1, fd); +} + +static int +addclose (int fd) +{ + return posix_spawn_file_actions_addclose (&actions, fd); +} + +static void +all_functions (void) +{ + all_tests ("addopen", addopen); + all_tests ("adddup2", adddup2); + all_tests ("adddup2", adddup2_reverse); + all_tests ("adddup2", addclose); +} + +static int +do_test (void) +{ + /* Try to eliminate the file descriptor limit. */ + { + struct rlimit limit; + if (getrlimit (RLIMIT_NOFILE, &limit) < 0) + { + printf ("error: getrlimit: %m\n"); + return 1; + } + limit.rlim_cur = RLIM_INFINITY; + if (setrlimit (RLIMIT_NOFILE, &limit) < 0) + printf ("warning: setrlimit: %m\n"); + } + + maxfd = sysconf (_SC_OPEN_MAX); + printf ("info: _SC_OPEN_MAX: %ld\n", maxfd); + + invalid_fd = dup (0); + if (invalid_fd < 0) + { + printf ("error: dup: %m\n"); + return 1; + } + if (close (invalid_fd) < 0) + { + printf ("error: close: %m\n"); + return 1; + } + + int ret = posix_spawn_file_actions_init (&actions); + if (ret != 0) + { + errno = ret; + printf ("error: posix_spawn_file_actions_init: %m\n"); + return 1; + } + + all_functions (); + + ret = posix_spawn_file_actions_destroy (&actions); + if (ret != 0) + { + errno = ret; + printf ("error: posix_spawn_file_actions_destroy: %m\n"); + return 1; + } + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-posix_spawn-setsid.c b/REORG.TODO/posix/tst-posix_spawn-setsid.c new file mode 100644 index 0000000000..256bd721b8 --- /dev/null +++ b/REORG.TODO/posix/tst-posix_spawn-setsid.c @@ -0,0 +1,95 @@ +/* Test posix_spawn setsid attribute. + Copyright (C) 2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <spawn.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/resource.h> +#include <unistd.h> + +#include <support/check.h> + +static void +do_test_setsid (bool test_setsid) +{ + pid_t sid, child_sid; + int res; + + /* Current session ID. */ + sid = getsid(0); + if (sid == (pid_t) -1) + FAIL_EXIT1 ("getsid (0): %m"); + + posix_spawnattr_t attrp; + /* posix_spawnattr_init should not fail (it basically memset the + attribute). */ + posix_spawnattr_init (&attrp); + if (test_setsid) + { + res = posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID); + if (res != 0) + { + errno = res; + FAIL_EXIT1 ("posix_spawnattr_setflags: %m"); + } + } + + /* Program to run. */ + char *args[2] = { (char *) "true", NULL }; + pid_t child; + + res = posix_spawnp (&child, "true", NULL, &attrp, args, environ); + /* posix_spawnattr_destroy is noop. */ + posix_spawnattr_destroy (&attrp); + + if (res != 0) + { + errno = res; + FAIL_EXIT1 ("posix_spawnp: %m"); + } + + /* Child should have a different session ID than parent. */ + child_sid = getsid (child); + + if (child_sid == (pid_t) -1) + FAIL_EXIT1 ("getsid (%i): %m", child); + + if (test_setsid) + { + if (child_sid == sid) + FAIL_EXIT1 ("child session ID matched parent one"); + } + else + { + if (child_sid != sid) + FAIL_EXIT1 ("child session ID did not match parent one"); + } +} + +static int +do_test (void) +{ + do_test_setsid (false); + do_test_setsid (true); + + return 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/posix/tst-preadwrite-common.c b/REORG.TODO/posix/tst-preadwrite-common.c new file mode 100644 index 0000000000..9468ed85a9 --- /dev/null +++ b/REORG.TODO/posix/tst-preadwrite-common.c @@ -0,0 +1,86 @@ +/* Common definitions for pread and pwrite. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <error.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 () + +/* 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. */ +static char *name; +static int fd; + +static void +do_prepare (void) +{ + fd = create_temp_file ("tst-preadwrite.", &name); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot create temporary file"); +} + + +static ssize_t +do_test_with_offset (off_t offset) +{ + char buf[1000]; + char res[1000]; + int i; + ssize_t ret; + + 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; + ret = pwrite (fd, buf + 100, 100, offset + 100); + if (ret == -1) + error (EXIT_FAILURE, errno, "during pwrite"); + + for (i = 450; i < 600; ++i) + buf[i] = i; + ret = pwrite (fd, buf + 450, 150, offset + 450); + if (ret == -1) + error (EXIT_FAILURE, errno, "during pwrite"); + + ret = pread (fd, res, sizeof (buf) - 50, offset + 50); + if (ret == -1) + error (EXIT_FAILURE, errno, "during pread"); + + if (memcmp (buf + 50, res, ret) != 0) + { + printf ("error: read of pread != write of pwrite\n"); + return -1; + } + + return ret; +} diff --git a/REORG.TODO/posix/tst-preadwrite.c b/REORG.TODO/posix/tst-preadwrite.c new file mode 100644 index 0000000000..a428705c3f --- /dev/null +++ b/REORG.TODO/posix/tst-preadwrite.c @@ -0,0 +1,25 @@ +/* Tests for pread and pwrite. + Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include "tst-preadwrite-common.c" + +static int +do_test (void) +{ + return do_test_with_offset (0) == -1; +} diff --git a/REORG.TODO/posix/tst-preadwrite64.c b/REORG.TODO/posix/tst-preadwrite64.c new file mode 100644 index 0000000000..2ea3d4ac1f --- /dev/null +++ b/REORG.TODO/posix/tst-preadwrite64.c @@ -0,0 +1,55 @@ +/* Tests for pread64 and pwrite64. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define _FILE_OFFSET_BITS 64 +#include "tst-preadwrite-common.c" + +static int +do_test (void) +{ + ssize_t ret; + + ret = do_test_with_offset (0); + if (ret == -1) + return 1; + + /* Create a sparse file larger than 4GB to check if offset is handled + correctly in p{write,read}64. */ + off_t base_offset = UINT32_MAX + 2048LL; + ret = do_test_with_offset (base_offset); + if (ret == -1) + return 1; + + struct stat st; + if (fstat (fd, &st) == -1) + { + printf ("error: fstat on temporary file failed: %m"); + return 1; + } + + /* The file size should >= base_offset plus bytes read. */ + off_t expected_value = base_offset + ret; + if (st.st_size < expected_value) + { + printf ("error: file size less than expected (%jd > %jd)\n", + (intmax_t) expected_value, (intmax_t) st.st_size); + return 1; + } + + return 0; +} diff --git a/REORG.TODO/posix/tst-regex.c b/REORG.TODO/posix/tst-regex.c new file mode 100644 index 0000000000..df2c108be5 --- /dev/null +++ b/REORG.TODO/posix/tst-regex.c @@ -0,0 +1,505 @@ +/* Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 <stdint.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); + + +static int +do_test (void) +{ + const char *file; + int fd; + struct stat st; + int result; + char *inmem; + char *outmem; + size_t inlen; + size_t outlen; + + mtrace (); + + /* 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: %jd.%09jd sec\n", + (intmax_t) finish.tv_sec, (intmax_t) 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: %jd.%09jd sec\n", + (intmax_t) mintime.tv_sec, (intmax_t) 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: %jd.%09jd sec\n", + (intmax_t) finish.tv_sec, (intmax_t) 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: %jd.%09jd sec\n", + (intmax_t) mintime.tv_sec, (intmax_t) mintime.tv_nsec); + } +#endif + + /* Return an error if the number of matches found is not match we + expect. */ + return cnt != expected; +} + +/* If --timing is used we will need a larger timout. */ +#define TIMEOUT 50 +#define CMDLINE_OPTIONS \ + {"timing", no_argument, &timing, 1 }, +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-regex2.c b/REORG.TODO/posix/tst-regex2.c new file mode 100644 index 0000000000..0d82c2acdd --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/tst-regexloc.c b/REORG.TODO/posix/tst-regexloc.c new file mode 100644 index 0000000000..0dbd061973 --- /dev/null +++ b/REORG.TODO/posix/tst-regexloc.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2001-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <regex.h> +#include <locale.h> +#include <stdio.h> + +static int +do_test (void) +{ + 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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-rfc3484-2.c b/REORG.TODO/posix/tst-rfc3484-2.c new file mode 100644 index 0000000000..ee9281394b --- /dev/null +++ b/REORG.TODO/posix/tst-rfc3484-2.c @@ -0,0 +1,189 @@ +#include <stdbool.h> +#include <stdio.h> +#include <ifaddrs.h> +#include <stdint.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 +#define __qsort_r qsort_r + +void +attribute_hidden +__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen) +{ + *p1 = *p2 = true; + *in6ai = NULL; + *in6ailen = 0; +} + +void +attribute_hidden +__free_in6ai (struct in6addrinfo *ai) +{ +} + +void +attribute_hidden +__check_native (uint32_t a1_index, int *a1_native, + uint32_t a2_index, int *a2_native) +{ +} + +int +attribute_hidden +__idna_to_ascii_lz (const char *input, char **output, int flags) +{ + return 0; +} + +int +attribute_hidden +__idna_to_unicode_lzlz (const char *input, char **output, int flags) +{ + *output = NULL; + return 0; +} + +void +attribute_hidden +_res_hconf_init (void) +{ +} + +#undef USE_NSCD +#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; + scopes = default_scopes; + + struct sockaddr_in so1; + so1.sin_family = AF_INET; + so1.sin_addr.s_addr = h (0xc0a85f19); + /* Clear the rest of the structure to avoid warnings. */ + memset (so1.sin_zero, '\0', sizeof (so1.sin_zero)); + + 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]; + size_t order[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; + results[0].prefixlen = 16; + results[0].index = 0; + memcpy (&results[0].source_addr, &so1, sizeof (so1)); + order[0] = 0; + + results[1].dest_addr = &ai2; + results[1].got_source_addr = true; + results[1].source_addr_len = sizeof (so2); + results[1].source_addr_flags = 0; + results[1].prefixlen = 16; + results[1].index = 0; + memcpy (&results[1].source_addr, &so2, sizeof (so2)); + order[1] = 1; + + + struct sort_result_combo combo = { .results = results, .nresults = 2 }; + qsort_r (order, 2, sizeof (order[0]), rfc3484_sort, &combo); + + int result = 0; + if (results[order[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; + results[1].prefixlen = 16; + results[1].index = 0; + memcpy (&results[1].source_addr, &so1, sizeof (so1)); + order[1] = 1; + + results[0].dest_addr = &ai2; + results[0].got_source_addr = true; + results[0].source_addr_len = sizeof (so2); + results[0].source_addr_flags = 0; + results[0].prefixlen = 16; + results[0].index = 0; + memcpy (&results[0].source_addr, &so2, sizeof (so2)); + order[0] = 0; + + + qsort_r (order, 2, sizeof (order[0]), rfc3484_sort, &combo); + + if (results[order[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/REORG.TODO/posix/tst-rfc3484-3.c b/REORG.TODO/posix/tst-rfc3484-3.c new file mode 100644 index 0000000000..c987366e4e --- /dev/null +++ b/REORG.TODO/posix/tst-rfc3484-3.c @@ -0,0 +1,161 @@ +#include <stdbool.h> +#include <stdio.h> +#include <ifaddrs.h> +#include <stdint.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 +#define __qsort_r qsort_r + +void +attribute_hidden +__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen) +{ + *p1 = *p2 = true; + *in6ai = NULL; + *in6ailen = 0; +} + +void +attribute_hidden +__free_in6ai (struct in6addrinfo *ai) +{ +} + +void +attribute_hidden +__check_native (uint32_t a1_index, int *a1_native, + uint32_t a2_index, int *a2_native) +{ +} + +int +attribute_hidden +__idna_to_ascii_lz (const char *input, char **output, int flags) +{ + return 0; +} + +int +attribute_hidden +__idna_to_unicode_lzlz (const char *input, char **output, int flags) +{ + *output = NULL; + return 0; +} + +void +attribute_hidden +_res_hconf_init (void) +{ +} + +#undef USE_NSCD +#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 (0xa0a86d1d) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a85d03) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a82c3d) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a86002) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a802f3) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a80810) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xa0a85e02) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xac162311) } }, + { .sin_family = AF_INET, .sin_addr = { h (0x0a324572) } } +}; +#define naddrs (sizeof (addrs) / sizeof (addrs[0])) +static struct addrinfo ais[naddrs]; +static struct sort_result results[naddrs]; +static size_t order[naddrs]; + +static const int expected[naddrs] = + { + 8, 0, 1, 2, 3, 4, 5, 6, 7 + }; + +static const struct scopeentry new_scopes[] = + { + { { { 169, 254, 0, 0 } }, h (0xffff0000), 2 }, + { { { 127, 0, 0, 0 } }, h (0xff000000), 2 }, + { { { 10, 0, 0, 0 } }, h (0xff000000), 5 }, + { { { 192, 168, 0, 0 } }, h(0xffff0000), 5 }, + { { { 0, 0, 0, 0 } }, h (0x00000000), 14 } + }; + + +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; + scopes= new_scopes; + + struct sockaddr_in so; + so.sin_family = AF_INET; + so.sin_addr.s_addr = h (0x0aa85f19); + /* Clear the rest of the structure to avoid warnings. */ + memset (so.sin_zero, '\0', sizeof (so.sin_zero)); + + 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; + results[i].prefixlen = 8; + results[i].index = 0; + + order[i] = i; + } + + struct sort_result_combo combo = { .results = results, .nresults = naddrs }; + qsort_r (order, naddrs, sizeof (order[0]), rfc3484_sort, &combo); + + int result = 0; + for (int i = 0; i < naddrs; ++i) + { + struct in_addr addr = ((struct sockaddr_in *) (results[order[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/REORG.TODO/posix/tst-rfc3484.c b/REORG.TODO/posix/tst-rfc3484.c new file mode 100644 index 0000000000..73c4dffcf5 --- /dev/null +++ b/REORG.TODO/posix/tst-rfc3484.c @@ -0,0 +1,153 @@ +#include <stdbool.h> +#include <stdio.h> +#include <ifaddrs.h> +#include <stdint.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 +#define __qsort_r qsort_r + +void +attribute_hidden +__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen) +{ + *p1 = *p2 = true; + *in6ai = NULL; + *in6ailen = 0; +} + +void +attribute_hidden +__free_in6ai (struct in6addrinfo *ai) +{ +} + +void +attribute_hidden +__check_native (uint32_t a1_index, int *a1_native, + uint32_t a2_index, int *a2_native) +{ +} + +int +attribute_hidden +__idna_to_ascii_lz (const char *input, char **output, int flags) +{ + return 0; +} + +int +attribute_hidden +__idna_to_unicode_lzlz (const char *input, char **output, int flags) +{ + *output = NULL; + return 0; +} + +void +attribute_hidden +_res_hconf_init (void) +{ +} + +#undef USE_NSCD +#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 (0x0aa85f19) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xac105f19) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0000219) } }, + { .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 size_t order[naddrs]; + +static int expected[naddrs] = + { + 9, 4, 3, 6, 5, 7, 8, 2, 0, 1 + }; + + +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; + scopes= default_scopes; + + struct sockaddr_in so; + so.sin_family = AF_INET; + so.sin_addr.s_addr = h (0xc0a85f19); + /* Clear the rest of the structure to avoid warnings. */ + memset (so.sin_zero, '\0', sizeof (so.sin_zero)); + + 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; + results[i].prefixlen = 8; + results[i].index = 0; + + order[i] = i; + } + + struct sort_result_combo combo = { .results = results, .nresults = naddrs }; + qsort_r (order, naddrs, sizeof (order[0]), rfc3484_sort, &combo); + + int result = 0; + for (int i = 0; i < naddrs; ++i) + { + struct in_addr addr = ((struct sockaddr_in *) (results[order[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/REORG.TODO/posix/tst-rxspencer-no-utf8.c b/REORG.TODO/posix/tst-rxspencer-no-utf8.c new file mode 100644 index 0000000000..62d4c7dd4c --- /dev/null +++ b/REORG.TODO/posix/tst-rxspencer-no-utf8.c @@ -0,0 +1 @@ +#include "tst-rxspencer.c" diff --git a/REORG.TODO/posix/tst-rxspencer.c b/REORG.TODO/posix/tst-rxspencer.c new file mode 100644 index 0000000000..f9e8eeb0fa --- /dev/null +++ b/REORG.TODO/posix/tst-rxspencer.c @@ -0,0 +1,561 @@ +/* Regular expression tests. + Copyright (C) 2003-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-spawn-static.c b/REORG.TODO/posix/tst-spawn-static.c new file mode 100644 index 0000000000..1b1d34fe2d --- /dev/null +++ b/REORG.TODO/posix/tst-spawn-static.c @@ -0,0 +1 @@ +#include "tst-spawn.c" diff --git a/REORG.TODO/posix/tst-spawn.c b/REORG.TODO/posix/tst-spawn.c new file mode 100644 index 0000000000..08d92bd7a7 --- /dev/null +++ b/REORG.TODO/posix/tst-spawn.c @@ -0,0 +1,261 @@ +/* Tests for spawn. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + +/* Descriptors for the temporary files. */ +static int temp_fd1 = -1; +static int temp_fd2 = -1; +static int temp_fd3 = -1; + +/* 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[]) +{ + /* We must not open any files in the restart case. */ + if (restart) + return; + + temp_fd1 = create_temp_file ("spawn", &name1); + temp_fd2 = create_temp_file ("spawn", &name2); + temp_fd3 = create_temp_file ("spawn", &name3); + if (temp_fd1 < 0 || temp_fd2 < 0 || temp_fd3 < 0) + exit (1); +} + + +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 fd4; + int status; + posix_spawn_file_actions_t actions; + char fd1name[18]; + char fd2name[18]; + char fd3name[18]; + char fd4name[18]; + char *name3_copy; + char *spargv[12]; + int i; + + /* We must have + - one or four parameters left if called initially + + path for ld.so optional + + "--library-path" optional + + the library path optional + + 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 : 2) && 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. */ + + /* Write something in the files. */ + if (write (temp_fd1, fd1string, strlen (fd1string)) != strlen (fd1string)) + error (EXIT_FAILURE, errno, "cannot write to first file"); + if (write (temp_fd2, fd2string, strlen (fd2string)) != strlen (fd2string)) + error (EXIT_FAILURE, errno, "cannot write to second file"); + if (write (temp_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 (temp_fd3); + + /* Tell `spawn' what to do. */ + if (posix_spawn_file_actions_init (&actions) != 0) + error (EXIT_FAILURE, errno, "posix_spawn_file_actions_init"); + /* Close `temp_fd1'. */ + if (posix_spawn_file_actions_addclose (&actions, temp_fd1) != 0) + error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose"); + /* We want to open the third file. */ + name3_copy = strdup (name3); + if (name3_copy == NULL) + error (EXIT_FAILURE, errno, "strdup"); + if (posix_spawn_file_actions_addopen (&actions, temp_fd3, name3_copy, + O_RDONLY, 0666) != 0) + error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen"); + /* Overwrite the name to check that a copy has been made. */ + memset (name3_copy, 'X', strlen (name3_copy)); + + /* We dup the second descriptor. */ + fd4 = MAX (2, MAX (temp_fd1, MAX (temp_fd2, temp_fd3))) + 1; + if (posix_spawn_file_actions_adddup2 (&actions, temp_fd2, fd4) != 0) + error (EXIT_FAILURE, errno, "posix_spawn_file_actions_adddup2"); + + /* Now spawn the process. */ + snprintf (fd1name, sizeof fd1name, "%d", temp_fd1); + snprintf (fd2name, sizeof fd2name, "%d", temp_fd2); + snprintf (fd3name, sizeof fd3name, "%d", temp_fd3); + snprintf (fd4name, sizeof fd4name, "%d", fd4); + + for (i = 0; i < (argc == (restart ? 6 : 5) ? 4 : 1); i++) + spargv[i] = argv[i + 1]; + spargv[i++] = (char *) "--direct"; + spargv[i++] = (char *) "--restart"; + spargv[i++] = fd1name; + spargv[i++] = fd2name; + spargv[i++] = fd3name; + spargv[i++] = fd4name; + spargv[i++] = name1; + spargv[i] = NULL; + + if (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ) != 0) + error (EXIT_FAILURE, errno, "posix_spawn"); + + /* Same test but with a NULL pid argument. */ + if (posix_spawn (NULL, 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"); + free (name3_copy); + + /* 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); + + return status; +} diff --git a/REORG.TODO/posix/tst-spawn2.c b/REORG.TODO/posix/tst-spawn2.c new file mode 100644 index 0000000000..73a37b6c01 --- /dev/null +++ b/REORG.TODO/posix/tst-spawn2.c @@ -0,0 +1,72 @@ +/* Further tests for spawn in case of invalid binary paths. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <spawn.h> +#include <error.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +#include <stdio.h> + +int +posix_spawn_test (void) +{ + /* Check if posix_spawn correctly returns an error and an invalid pid + by trying to spawn an invalid binary. */ + + const char *program = "/path/to/invalid/binary"; + char * const args[] = { 0 }; + pid_t pid = -1; + + int ret = posix_spawn (&pid, program, 0, 0, args, environ); + if (ret != ENOENT) + error (EXIT_FAILURE, errno, "posix_spawn"); + + /* POSIX states the value returned on pid variable in case of an error + is not specified. GLIBC will update the value iff the child + execution is successful. */ + if (pid != -1) + error (EXIT_FAILURE, errno, "posix_spawn returned pid != -1"); + + /* Check if no child is actually created. */ + ret = waitpid (-1, NULL, 0); + if (ret != -1 || errno != ECHILD) + error (EXIT_FAILURE, errno, "waitpid"); + + /* Same as before, but with posix_spawnp. */ + char *args2[] = { (char*) program, 0 }; + + ret = posix_spawnp (&pid, args2[0], 0, 0, args2, environ); + if (ret != ENOENT) + error (EXIT_FAILURE, errno, "posix_spawnp"); + + if (pid != -1) + error (EXIT_FAILURE, errno, "posix_spawnp returned pid != -1"); + + ret = waitpid (-1, NULL, 0); + if (ret != -1 || errno != ECHILD) + error (EXIT_FAILURE, errno, "waitpid"); + + return 0; +} + +#define TEST_FUNCTION posix_spawn_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/posix/tst-spawn3.c b/REORG.TODO/posix/tst-spawn3.c new file mode 100644 index 0000000000..8577b03d01 --- /dev/null +++ b/REORG.TODO/posix/tst-spawn3.c @@ -0,0 +1,189 @@ +/* Check posix_spawn add file actions. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <spawn.h> +#include <error.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> +#include <sys/resource.h> + +static int do_test (void); +#define TEST_FUNCTION do_test () +#include <test-skeleton.c> + +static int +do_test (void) +{ + /* The test checks if posix_spawn open file action close the file descriptor + before opening a new one in case the input file descriptor is already + opened. It does by exhausting all file descriptors on the process before + issue posix_spawn. It then issues a posix_spawn for '/bin/sh echo $$' + and add two rules: + + 1. Redirect stdout to a temporary filepath + 2. Redirect stderr to stdout + + If the implementation does not close the file 1. will fail with + EMFILE. */ + + struct rlimit rl; + int max_fd = 24; + + /* Set maximum number of file descriptor to a low value to avoid open + too many files in environments where RLIMIT_NOFILE is large and to + limit the array size to track the opened file descriptors. */ + + if (getrlimit (RLIMIT_NOFILE, &rl) == -1) + { + printf ("error: getrlimit RLIMIT_NOFILE failed"); + exit (EXIT_FAILURE); + } + + max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd); + rl.rlim_cur = max_fd; + + if (setrlimit (RLIMIT_NOFILE, &rl) == 1) + { + printf ("error: setrlimit RLIMIT_NOFILE to %u failed", max_fd); + exit (EXIT_FAILURE); + } + + /* Exhauste the file descriptor limit with temporary files. */ + int files[max_fd]; + int nfiles = 0; + for (;;) + { + int fd = create_temp_file ("tst-spawn3.", NULL); + if (fd == -1) + { + if (errno != EMFILE) + { + printf ("error: create_temp_file returned -1 with " + "errno != EMFILE\n"); + exit (EXIT_FAILURE); + } + break; + } + files[nfiles++] = fd; + } + + posix_spawn_file_actions_t a; + if (posix_spawn_file_actions_init (&a) != 0) + { + puts ("error: spawn_file_actions_init failed"); + exit (EXIT_FAILURE); + } + + /* Executes a /bin/sh echo $$ 2>&1 > /tmp/tst-spawn3.pid . */ + const char pidfile[] = "/tmp/tst-spawn3.pid"; + if (posix_spawn_file_actions_addopen (&a, STDOUT_FILENO, pidfile, O_WRONLY | + O_CREAT | O_TRUNC, 0644) != 0) + { + puts ("error: spawn_file_actions_addopen failed"); + exit (EXIT_FAILURE); + } + + if (posix_spawn_file_actions_adddup2 (&a, STDOUT_FILENO, STDERR_FILENO) != 0) + { + puts ("error: spawn_file_actions_addclose"); + exit (EXIT_FAILURE); + } + + /* Since execve (called by posix_spawn) might require to open files to + actually execute the shell script, setup to close the temporary file + descriptors. */ + for (int i=0; i<nfiles; i++) + { + if (posix_spawn_file_actions_addclose (&a, files[i])) + { + printf ("error: posix_spawn_file_actions_addclose failed"); + exit (EXIT_FAILURE); + } + } + + char *spawn_argv[] = { (char *) _PATH_BSHELL, (char *) "-c", + (char *) "echo $$", NULL }; + pid_t pid; + if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL) != 0) + { + puts ("error: posix_spawn failed"); + exit (EXIT_FAILURE); + } + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("error: waitpid failed"); + exit (EXIT_FAILURE); + } + + /* Close the temporary files descriptor so it can check posix_spawn + output. */ + for (int i=0; i<nfiles; i++) + { + if (close (files[i])) + { + printf ("error: close failed\n"); + exit (EXIT_FAILURE); + } + } + + int pidfd = open (pidfile, O_RDONLY); + if (pidfd == -1) + { + printf ("error: open pidfile failed\n"); + exit (EXIT_FAILURE); + } + + char buf[64]; + ssize_t n; + if ((n = read (pidfd, buf, sizeof (buf))) < 0) + { + printf ("error: read pidfile failed\n"); + exit (EXIT_FAILURE); + } + + unlink (pidfile); + + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + if (*endp != '\n') + { + printf ("error: didn't parse whole line: \"%s\"\n", buf); + exit (EXIT_FAILURE); + } + if (endp == buf) + { + puts ("error: read empty line"); + exit (EXIT_FAILURE); + } + + if (rpid != pid) + { + printf ("error: found \"%s\", expected PID %ld\n", buf, (long int) pid); + exit (EXIT_FAILURE); + } + + return 0; +} diff --git a/REORG.TODO/posix/tst-sysconf.c b/REORG.TODO/posix/tst-sysconf.c new file mode 100644 index 0000000000..105c7c2625 --- /dev/null +++ b/REORG.TODO/posix/tst-sysconf.c @@ -0,0 +1,120 @@ +#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), +#ifdef _POSIX_PRIORITIZED_IO + N (PRIORITIZED_IO), +#endif +#ifdef _POSIX_PRIORITY_SCHEDULING + N (PRIORITY_SCHEDULING), +#endif + 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), +#ifdef _POSIX_SYNCHRONIZED_IO + N (SYNCHRONIZED_IO), +#endif + 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 200809L + 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/REORG.TODO/posix/tst-truncate-common.c b/REORG.TODO/posix/tst-truncate-common.c new file mode 100644 index 0000000000..ecb0dff324 --- /dev/null +++ b/REORG.TODO/posix/tst-truncate-common.c @@ -0,0 +1,88 @@ +/* Common f{truncate} tests definitions. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.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 *temp_filename; +static int temp_fd; + +static void +do_prepare (void) +{ + temp_fd = create_temp_file ("tst-trucate.", &temp_filename); + if (temp_fd == -1) + { + printf ("cannot create temporary file: %m\n"); + exit (1); + } +} + +#define FAIL(str) \ + do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0) + +static int +do_test_with_offset (off_t offset) +{ + struct stat st; + char buf[1000]; + + memset (buf, 0xcf, sizeof (buf)); + + if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf)) + FAIL ("write failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf))) + FAIL ("initial size wrong"); + + if (ftruncate (temp_fd, offset + 800) < 0) + FAIL ("size reduction with ftruncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800)) + FAIL ("size after reduction with ftruncate is incorrect"); + + /* 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 (temp_fd, offset + 1200) < 0) + FAIL ("size increate with ftruncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200)) + FAIL ("size after increase is incorrect"); + + if (truncate (temp_filename, offset + 800) < 0) + FAIL ("size reduction with truncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800)) + FAIL ("size after reduction with truncate incorrect"); + + /* 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 (temp_filename, (offset + 1200)) < 0) + FAIL ("size increase with truncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200)) + FAIL ("size increase with truncate is incorrect"); + + return 0; +} diff --git a/REORG.TODO/posix/tst-truncate.c b/REORG.TODO/posix/tst-truncate.c new file mode 100644 index 0000000000..7ac4f6db60 --- /dev/null +++ b/REORG.TODO/posix/tst-truncate.c @@ -0,0 +1,26 @@ +/* Tests for ftruncate and truncate. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include "tst-truncate-common.c" + +static int +do_test (void) +{ + return do_test_with_offset (0); +} diff --git a/REORG.TODO/posix/tst-truncate64.c b/REORG.TODO/posix/tst-truncate64.c new file mode 100644 index 0000000000..55d55cc443 --- /dev/null +++ b/REORG.TODO/posix/tst-truncate64.c @@ -0,0 +1,38 @@ +/* Tests for ftruncate64 and truncate64. + Copyright (C) 2000-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define _FILE_OFFSET_BITS 64 +#include "tst-truncate-common.c" + +static int +do_test (void) +{ + int ret; + + ret = do_test_with_offset (0); + if (ret == -1) + return -1; + + off_t base_offset = UINT32_MAX + 512LL; + ret = do_test_with_offset (base_offset); + if (ret == -1) + return 1; + + return 0; +} diff --git a/REORG.TODO/posix/tst-vfork1.c b/REORG.TODO/posix/tst-vfork1.c new file mode 100644 index 0000000000..fa5f91fda6 --- /dev/null +++ b/REORG.TODO/posix/tst-vfork1.c @@ -0,0 +1,149 @@ +/* Test for vfork functions. + Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-vfork2.c b/REORG.TODO/posix/tst-vfork2.c new file mode 100644 index 0000000000..ee0955072d --- /dev/null +++ b/REORG.TODO/posix/tst-vfork2.c @@ -0,0 +1,198 @@ +/* Test for vfork functions. + Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/tst-vfork3.c b/REORG.TODO/posix/tst-vfork3.c new file mode 100644 index 0000000000..80898b3e41 --- /dev/null +++ b/REORG.TODO/posix/tst-vfork3.c @@ -0,0 +1,175 @@ +/* Test for vfork functions. + Copyright (C) 2007-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <mcheck.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/wait.h> + +static int do_test (void); +static void do_prepare (void); +char *tmpdirname; + +#define TEST_FUNCTION do_test () +#define PREPARE(argc, argv) do_prepare () +#include "../test-skeleton.c" + +static void +run_script (const char *script, char *const argv[]) +{ + for (size_t i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + FAIL_EXIT1 ("vfork failed: %m"); + else if (pid == 0) + { + execvp (script, argv); + _exit (errno); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + FAIL_EXIT1 ("waitpid failed"); + else if (status != 0) + { + if (WIFEXITED (status)) + FAIL_EXIT1 ("%s failed with status %d\n", script, + WEXITSTATUS (status)); + else + FAIL_EXIT1 ("%s killed by signal %d\n", script, + WTERMSIG (status)); + } + } +} + +static int +do_test (void) +{ + mtrace (); + + const char *path = getenv ("PATH"); + if (path == NULL) + path = "/bin"; + char pathbuf[strlen (tmpdirname) + 1 + strlen (path) + 1]; + strcpy (stpcpy (stpcpy (pathbuf, tmpdirname), ":"), path); + if (setenv ("PATH", pathbuf, 1) < 0) + { + puts ("setenv failed"); + return 1; + } + + /* Although manual states first argument should be the script name itself, + current execv{p,e} implementation allows it. */ + char *argv00[] = { NULL }; + run_script ("script0.sh", argv00); + + char *argv01[] = { (char*) "script0.sh", NULL }; + run_script ("script0.sh", argv01); + + char *argv1[] = { (char *) "script1.sh", (char *) "1", NULL }; + run_script ("script1.sh", argv1); + + char *argv2[] = { (char *) "script2.sh", (char *) "2", NULL }; + run_script ("script2.sh", argv2); + + /* Same as before but with execlp. */ + for (size_t i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + { + printf ("vfork failed: %m\n"); + return 1; + } + else if (pid == 0) + { + execlp ("script2.sh", "script2.sh", "3", NULL); + _exit (errno); + } + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + else if (status != 0) + { + printf ("script2.sh failed with status %d\n", status); + return 1; + } + } + + unsetenv ("PATH"); + char *argv4[] = { (char *) "echo", (char *) "script 4", NULL }; + run_script ("echo", argv4); + + return 0; +} + +static void +create_script (const char *script, const char *contents, size_t size) +{ + int fd = open (script, O_WRONLY | O_CREAT, 0700); + if (fd < 0 + || TEMP_FAILURE_RETRY (write (fd, contents, size)) != size + || fchmod (fd, S_IRUSR | S_IXUSR) < 0) + FAIL_EXIT1 ("could not write %s\n", script); + close (fd); +} + +static void +do_prepare (void) +{ + size_t len = strlen (test_dir) + sizeof ("/tst-vfork3.XXXXXX"); + tmpdirname = malloc (len); + if (tmpdirname == NULL) + FAIL_EXIT1 ("out of memory"); + strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX"); + + tmpdirname = mkdtemp (tmpdirname); + if (tmpdirname == NULL) + FAIL_EXIT1 ("could not create temporary directory"); + + char script0[len + sizeof "/script0.sh"]; + char script1[len + sizeof "/script1.sh"]; + char script2[len + sizeof "/script2.sh"]; + + strcpy (stpcpy (script0, tmpdirname), "/script0.sh"); + strcpy (stpcpy (script1, tmpdirname), "/script1.sh"); + strcpy (stpcpy (script2, tmpdirname), "/script2.sh"); + + add_temp_file (tmpdirname); + add_temp_file (script0); + add_temp_file (script1); + add_temp_file (script2); + + const char content0[] = "#!/bin/sh\necho empty\n"; + create_script (script0, content0, sizeof content0); + + const char content1[] = "#!/bin/sh\necho script $1\n"; + create_script (script1, content1, sizeof content1); + + const char content2[] = "echo script $1\n"; + create_script (script2, content2, sizeof content2); +} diff --git a/REORG.TODO/posix/tst-waitid.c b/REORG.TODO/posix/tst-waitid.c new file mode 100644 index 0000000000..436da6492c --- /dev/null +++ b/REORG.TODO/posix/tst-waitid.c @@ -0,0 +1,520 @@ +/* Tests for waitid. + Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (before waitid)", 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 (before waitid)", 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); + } + + /* Give the child a chance to stop. The waitpid call below will block + until it has stopped, but if we are real quick and enter the waitpid + system call before the SIGCHLD has been generated, then it will be + discarded and never delivered. */ + sleep (3); + + 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 (after waitpid)", 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 (before waitpid)", 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/REORG.TODO/posix/tstgetopt.c b/REORG.TODO/posix/tstgetopt.c new file mode 100644 index 0000000000..97ae2ef251 --- /dev/null +++ b/REORG.TODO/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/REORG.TODO/posix/uname-values.h b/REORG.TODO/posix/uname-values.h new file mode 100644 index 0000000000..ecc98b1b2c --- /dev/null +++ b/REORG.TODO/posix/uname-values.h @@ -0,0 +1,28 @@ +/* Constant values for the uname function to return. Generic version. + Copyright (C) 2015-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* This file exists so that it can be replaced by sysdeps variants. + It must define these macros with string values: + UNAME_SYSNAME + UNAME_RELEASE + UNAME_VERSION + UNAME_MACHINE + If there is no sysdeps file, this file will just proxy to the file + created by posix/Makefile. */ + +#include <config-name.h> diff --git a/REORG.TODO/posix/uname.c b/REORG.TODO/posix/uname.c new file mode 100644 index 0000000000..afe1e397ea --- /dev/null +++ b/REORG.TODO/posix/uname.c @@ -0,0 +1,65 @@ +/* uname -- Report basic information about the system. Generic version. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <string.h> +#include <sys/utsname.h> +#include <unistd.h> + +/* This file defines UNAME_* to string constants. */ +#include <uname-values.h> + +/* Put information about the system in NAME. */ +int +__uname (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/REORG.TODO/posix/unistd.h b/REORG.TODO/posix/unistd.h new file mode 100644 index 0000000000..32b0f4898f --- /dev/null +++ b/REORG.TODO/posix/unistd.h @@ -0,0 +1,1172 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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'. */ + +#ifdef __USE_XOPEN2K8 +/* POSIX Standard approved as ISO/IEC 9945-1 as of September 2008. */ +# define _POSIX_VERSION 200809L +#elif defined __USE_XOPEN2K +/* POSIX Standard approved as ISO/IEC 9945-1 as of December 2001. */ +# define _POSIX_VERSION 200112L +#elif defined __USE_POSIX199506 +/* POSIX Standard approved as ISO/IEC 9945-1 as of June 1995. */ +# define _POSIX_VERSION 199506L +#elif defined __USE_POSIX199309 +/* POSIX Standard approved as ISO/IEC 9945-1 as of September 1993. */ +# define _POSIX_VERSION 199309L +#else +/* POSIX Standard approved as ISO/IEC 9945-1 as of September 1990. */ +# define _POSIX_VERSION 199009L +#endif + +/* These are not #ifdef __USE_POSIX2 because they are + in the theoretically application-owned namespace. */ + +#ifdef __USE_XOPEN2K8 +# define __POSIX2_THIS_VERSION 200809L +/* The utilities on GNU systems also correspond to this version. */ +#elif defined __USE_XOPEN2K +/* The utilities on GNU systems also correspond to this version. */ +# define __POSIX2_THIS_VERSION 200112L +#elif defined __USE_POSIX199506 +/* The utilities on GNU systems also correspond to this version. */ +# define __POSIX2_THIS_VERSION 199506L +#else +/* The utilities on GNU systems also correspond to this version. */ +# define __POSIX2_THIS_VERSION 199209L +#endif + +/* The utilities on GNU systems also correspond to this version. */ +#define _POSIX2_VERSION __POSIX2_THIS_VERSION + +/* This symbol was required until the 2001 edition of POSIX. */ +#define _POSIX2_C_VERSION __POSIX2_THIS_VERSION + +/* If defined, the implementation supports the + C Language Bindings Option. */ +#define _POSIX2_C_BIND __POSIX2_THIS_VERSION + +/* If defined, the implementation supports the + C Language Development Utilities Option. */ +#define _POSIX2_C_DEV __POSIX2_THIS_VERSION + +/* If defined, the implementation supports the + Software Development Utilities Option. */ +#define _POSIX2_SW_DEV __POSIX2_THIS_VERSION + +/* If defined, the implementation supports the + creation of locales with the localedef utility. */ +#define _POSIX2_LOCALEDEF __POSIX2_THIS_VERSION + +/* X/Open version number to which the library conforms. It is selectable. */ +#ifdef __USE_XOPEN2K8 +# define _XOPEN_VERSION 700 +#elif defined __USE_XOPEN2K +# define _XOPEN_VERSION 600 +#elif defined __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. */ +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +# 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_XOPEN_EXTENDED || defined __USE_XOPEN2K +# ifndef __intptr_t_defined +typedef __intptr_t intptr_t; +# define __intptr_t_defined +# endif +#endif + +#if defined __USE_MISC || 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. */ +# ifdef __USE_GNU +# define SEEK_DATA 3 /* Seek to next data. */ +# define SEEK_HOLE 4 /* Seek to next hole. */ +# endif +#endif + +#if defined __USE_MISC && !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; + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 +# 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; + +#ifdef __USE_GNU +/* Same as pipe but apply flags passed in FLAGS to the new file + descriptors. */ +extern int pipe2 (int __pipedes[2], int __flags) __THROW __wur; +#endif + +/* 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_XOPEN_EXTENDED && !defined __USE_XOPEN2K8) \ + || defined __USE_MISC +/* 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_XOPEN_EXTENDED || defined __USE_XOPEN2K8 +/* 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 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_XOPEN_EXTENDED || defined __USE_XOPEN2K8 +/* 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_XOPEN_EXTENDED && !defined __USE_XOPEN2K8) \ + || defined __USE_MISC +/* 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; + +#ifdef __USE_GNU +/* Duplicate FD to FD2, closing FD2 and making it open on the same + file while setting flags according to FLAGS. */ +extern int dup3 (int __fd, int __fd2, int __flags) __THROW; +#endif + +/* 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, 2)); + +#ifdef __USE_XOPEN2K8 +/* 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 __nonnull ((2)); +#endif + + +/* Execute PATH with arguments ARGV and environment from `environ'. */ +extern int execv (const char *__path, char *const __argv[]) + __THROW __nonnull ((1, 2)); + +/* 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, 2)); + +/* 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, 2)); + +/* 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, 2)); + +/* 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, 2)); + +#ifdef __USE_GNU +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from `environ'. */ +extern int execvpe (const char *__file, char *const __argv[], + char *const __envp[]) + __THROW __nonnull ((1, 2)); +#endif + + +#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; + +#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. */ +extern __pid_t getpgrp (void) __THROW; + +/* Get the process group ID of process PID. */ +extern __pid_t __getpgid (__pid_t __pid) __THROW; +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 +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_MISC || 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. + + GNU provides the POSIX.1 function. */ + +/* 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; + +#endif /* Use misc or X/Open. */ + +/* 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; + +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 +/* 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 __wur; + +#if defined __USE_MISC || 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 __wur; +#endif + +#ifdef __USE_XOPEN2K +/* Set the effective user ID of the calling process to UID. */ +extern int seteuid (__uid_t __uid) __THROW __wur; +#endif /* Use POSIX.1-2001. */ + +/* 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 __wur; + +#if defined __USE_MISC || 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 __wur; +#endif + +#ifdef __USE_XOPEN2K +/* Set the effective group ID of the calling process to GID. */ +extern int setegid (__gid_t __gid) __THROW __wur; +#endif /* Use POSIX.1-2001. */ + +#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 __wur; + +/* 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 __wur; +#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) __THROWNL; + +#if (defined __USE_XOPEN_EXTENDED && !defined __USE_XOPEN2K8) \ + || defined __USE_MISC +/* 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 misc or XPG < 7. */ + + +/* 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; + +#ifdef __USE_MISC +/* 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_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 POSIX.1-2001. */ + +#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 point and therefore not + marked with __THROW. */ +extern char *getlogin (void); +#ifdef __USE_POSIX199506 +/* 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 point and therefore not + marked with __THROW. */ +extern int getlogin_r (char *__name, size_t __name_len) __nonnull ((1)); +#endif + +#ifdef __USE_MISC +/* 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. */ +# include <bits/getopt_posix.h> +#endif + + +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K +/* 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_MISC +/* 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 misc. */ + + +#if defined __USE_MISC || (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 misc || X/Open. */ + + +/* 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); + + +#ifdef __USE_GNU +/* Make all changes done to all files on the file system associated + with FD actually appear on disk. */ +extern int syncfs (int __fd) __THROW; +#endif + + +#if defined __USE_MISC || 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; + + +# if defined __USE_MISC || !defined __USE_XOPEN2K +/* 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; +# endif + +#endif /* Use misc || X/Open Unix. */ + + +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 + +/* 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 X/Open Unix || POSIX 2008. */ + +#if defined __USE_POSIX199309 \ + || 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 POSIX.1b || X/Open Unix || XPG6. */ + + +#if (defined __USE_XOPEN_EXTENDED && !defined __USE_XOPEN2K) \ + || defined __USE_MISC + +/* 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); +#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 *__glibc_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 + + +/* Prior to Issue 6, the Single Unix Specification required these + prototypes to appear in this header. They are also found in + <stdio.h>. */ +#if defined __USE_XOPEN && !defined __USE_XOPEN2K +/* Return the name of the controlling terminal. */ +extern char *ctermid (char *__s) __THROW; + +/* Return the name of the current user. */ +extern char *cuserid (char *__s); +#endif + + +/* Unix98 requires this function to be declared here. In other + standards it is in <pthread.h>. */ +#if defined __USE_UNIX98 && !defined __USE_XOPEN2K +extern int pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)) __THROW; +#endif + +#ifdef __USE_MISC +/* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on + success or -1 on error. */ +int getentropy (void *__buffer, size_t __length) __wur; +#endif + +/* Define some macros helping to catch buffer overflows. */ +#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +# include <bits/unistd.h> +#endif + +__END_DECLS + +#endif /* unistd.h */ diff --git a/REORG.TODO/posix/vfork.c b/REORG.TODO/posix/vfork.c new file mode 100644 index 0000000000..07440d7361 --- /dev/null +++ b/REORG.TODO/posix/vfork.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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/REORG.TODO/posix/wait.c b/REORG.TODO/posix/wait.c new file mode 100644 index 0000000000..ccead487bd --- /dev/null +++ b/REORG.TODO/posix/wait.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (int *stat_loc) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (wait) + +weak_alias (__wait, wait) diff --git a/REORG.TODO/posix/wait.h b/REORG.TODO/posix/wait.h new file mode 100644 index 0000000000..d01b81125f --- /dev/null +++ b/REORG.TODO/posix/wait.h @@ -0,0 +1 @@ +#include <sys/wait.h> diff --git a/REORG.TODO/posix/wait3.c b/REORG.TODO/posix/wait3.c new file mode 100644 index 0000000000..8604603f33 --- /dev/null +++ b/REORG.TODO/posix/wait3.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 (int *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) diff --git a/REORG.TODO/posix/wait4.c b/REORG.TODO/posix/wait4.c new file mode 100644 index 0000000000..34ac71a895 --- /dev/null +++ b/REORG.TODO/posix/wait4.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +pid_t +__wait4 (__pid_t pid, int *stat_loc, int options, struct rusage *usage) +{ + __set_errno (ENOSYS); + return (pid_t) -1; +} +stub_warning (wait4) + +weak_alias (__wait4, wait4) diff --git a/REORG.TODO/posix/waitid.c b/REORG.TODO/posix/waitid.c new file mode 100644 index 0000000000..9a0216ac9a --- /dev/null +++ b/REORG.TODO/posix/waitid.c @@ -0,0 +1,30 @@ +/* Stub version of waitid. + Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> + +int +__waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + __set_errno (ENOSYS); + return -1; +} +weak_alias (__waitid, waitid) diff --git a/REORG.TODO/posix/waitpid.c b/REORG.TODO/posix/waitpid.c new file mode 100644 index 0000000000..7d527c984b --- /dev/null +++ b/REORG.TODO/posix/waitpid.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 +__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; +} +libc_hidden_def (__waitpid) +weak_alias (__waitpid, waitpid) + +stub_warning (waitpid) diff --git a/REORG.TODO/posix/wordexp-test.c b/REORG.TODO/posix/wordexp-test.c new file mode 100644 index 0000000000..17ae812346 --- /dev/null +++ b/REORG.TODO/posix/wordexp-test.c @@ -0,0 +1,560 @@ +/* Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <pwd.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <wordexp.h> +#include <libc-pointer-arith.h> + +#define IFS " \n\t" + +extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden"))); +extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *); + +static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void)) +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} + +/* Number of forks seen. */ +static int registered_forks; + +/* For each fork increment the fork count. */ +static void +register_fork (void) +{ + registered_forks++; +} + +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 }, + /* Test for CVE-2014-7817. We test 3 combinations of command + substitution inside an arithmetic expression to make sure that + no commands are executed and error is returned. */ + { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS }, + { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS }, + { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS }, + + { WRDE_SYNTAX, NULL, "`\\", 0, 0, { NULL, }, IFS }, /* BZ 18042 */ + { WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS }, /* BZ 18043 */ + { WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS }, /* BZ 18043#c4 */ + { WRDE_SYNTAX, NULL, "$[1/0]", WRDE_NOCMD, 0, {NULL, }, IFS }, /* BZ 18100 */ + + { -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; + } + + /* If we are not allowed to do command substitution, we install + fork handlers to verify that no forks happened. No forks should + happen at all if command substitution is disabled. */ + if (__app_register_atfork (register_fork, NULL, NULL) != 0) + { + printf ("Failed to register fork handler.\n"); + 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; + } + + /* Integer overflow in division. */ + { + static const char *const numbers[] = { + "0", + "1", + "65536", + "2147483648", + "4294967296" + "9223372036854775808", + "18446744073709551616", + "170141183460469231731687303715884105728", + "340282366920938463463374607431768211456", + NULL + }; + + for (const char *const *num = numbers; *num; ++num) + { + wordexp_t p; + char pattern[256]; + snprintf (pattern, sizeof (pattern), "$[(-%s)/(-1)]", *num); + int ret = wordexp (pattern, &p, WRDE_NOCMD); + if (ret == 0) + { + if (p.we_wordc != 1 || strcmp (p.we_wordv[0], *num) != 0) + { + printf ("Integer overflow for \"%s\" failed", pattern); + ++fail; + } + wordfree (&p); + } + else if (ret != WRDE_SYNTAX) + { + printf ("Integer overflow for \"%s\" failed with %d", + pattern, ret); + ++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 const char * +at_page_end (const char *words) +{ + const int pagesize = getpagesize (); + char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + + if (start == MAP_FAILED) + return start; + + if (mprotect (start + pagesize, pagesize, PROT_NONE)) + { + munmap (start, 2 * pagesize); + return MAP_FAILED; + } + + /* Includes terminating NUL. */ + const size_t words_size = strlen (words) + 1; + char *words_start = start + pagesize - words_size; + memcpy (words_start, words, words_size); + + return words_start; +} + +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); + fflush (NULL); + const char *words = at_page_end (tc->words); + + if (tc->flags & WRDE_NOCMD) + registered_forks = 0; + + 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 (words, &we, tc->flags); + + if ((tc->flags & WRDE_NOCMD) + && (registered_forks > 0)) + { + printf ("FAILED fork called for WRDE_NOCMD\n"); + return 1; + } + + 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); + + const int page_size = getpagesize (); + char *start = (char *) PTR_ALIGN_DOWN (words, page_size); + + if (munmap (start, 2 * page_size) != 0) + return 1; + + fflush (NULL); + return bzzzt; +} diff --git a/REORG.TODO/posix/wordexp-tst.sh b/REORG.TODO/posix/wordexp-tst.sh new file mode 100755 index 0000000000..fb571a74cc --- /dev/null +++ b/REORG.TODO/posix/wordexp-tst.sh @@ -0,0 +1,183 @@ +#!/bin/sh +# Test for wordexp(3). +# Copyright (C) 1998-2017 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, see +# <http://www.gnu.org/licenses/>. + +set -e + +# 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 +test_program_prefix_before_env=$1; shift +run_program_env=$1; shift +test_program_prefix_after_env=$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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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 + +${test_program_prefix_before_env} ${run_program_env} IFS="$IFS" \ +${test_program_prefix_after_env} \ +${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/REORG.TODO/posix/wordexp.c b/REORG.TODO/posix/wordexp.c new file mode 100644 index 0000000000..dfc41736e6 --- /dev/null +++ b/REORG.TODO/posix/wordexp.c @@ -0,0 +1,2465 @@ +/* POSIX.2 wordexp implementation. + Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 <stdbool.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> +#include <wchar.h> +#include <wordexp.h> +#include <kernel-features.h> + +#include <libc-lock.h> +#include <_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; + + /* Division by zero or integer overflow. */ + if (arg == 0 || (arg == -1 && *result == LONG_MIN)) + 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. */ + if (__glibc_likely (fildes[1] != STDOUT_FILENO)) + { + __dup2 (fildes[1], STDOUT_FILENO); + __close (fildes[1]); + } + else + /* Reset the close-on-exec flag (if necessary). */ + __fcntl (fildes[1], F_SETFD, 0); + + /* Redirect stderr to /dev/null if we have to. */ + if (showerr == 0) + { + struct stat64 st; + int fd; + __close (STDERR_FILENO); + fd = __open (_PATH_DEVNULL, O_WRONLY); + if (fd >= 0 && fd != STDERR_FILENO) + { + __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; + + /* Do nothing if command substitution should not succeed. */ + if (flags & WRDE_NOCMD) + return WRDE_CMDSUB; + + /* Don't fork() unless necessary */ + if (!comm || !*comm) + return 0; + + if (__pipe2 (fildes, O_CLOEXEC) < 0) + return WRDE_NOSPACE; + + again: + if ((pid = __fork ()) < 0) + { + /* Bad */ + __close (fildes[0]); + __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 read returned 0 then the process has closed its + stdout. Don't use WNOHANG in that case to avoid busy + looping until the process eventually exits. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, + buflen == 0 ? 0 : 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 read returned 0 then the process has closed its + stdout. Don't use WNOHANG in that case to avoid busy + looping until the process eventually exits. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, + buflen == 0 ? 0 : 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; +} + +#define CHAR_IN_SET(ch, char_set) \ + (memchr (char_set "", ch, sizeof (char_set) - 1) != NULL) + +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 (CHAR_IN_SET (words[*offset], "*@$")) + { + /* 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 (!CHAR_IN_SET (words[1 + *offset], "-=?+")) + 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) + 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) + 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; +} + +#undef CHAR_IN_SET + +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); + } + } + + (*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; + } + + 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 '`': + ++(*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 '`': + ++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/REORG.TODO/posix/wordexp.h b/REORG.TODO/posix/wordexp.h new file mode 100644 index 0000000000..a0e813b9fc --- /dev/null +++ b/REORG.TODO/posix/wordexp.h @@ -0,0 +1,70 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 */ |