1d83d0dcc8ffdceb3b63d99f5e495c0aeea0f236
[kopensolaris-gnu/glibc.git] / conform / conformtest.pl
1 #! /usr/bin/perl
2
3 $CC = "gcc";
4 $CFLAGS = "-I. '-D__attribute__(x)=' -D_XOPEN_SOURCE=500";
5
6 # List of the headers we are testing.
7 @headers = ("math.h", "locale.h", "libgen.h", "langinfo.h", "iso646.h",
8             "inttypes.h", "iconv.h", "grp.h", "glob.h", "ftw.h", "fnmatch.h",
9             "fmtmsg.h", "float.h", "fcntl.h", "errno.h", "dlfcn.h", "dirent.h",
10             "ctype.h", "cpio.h", "assert.h", "aio.h");
11
12 # These are the ISO C9x keywords.
13 @keywords = ('auto', 'break', 'case', 'char', 'const', 'continue', 'default',
14              'do', 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto',
15              'if', 'inline', 'int', 'long', 'register', 'restrict', 'return',
16              'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
17              'typedef', 'union', 'unsigned', 'void', 'volatile', 'while');
18
19 # Make an hash table from this information.
20 while ($#keywords) {
21   $iskeyword{pop (@keywords)} = 1;
22 }
23
24 $tmpdir = "/tmp";
25
26 $verbose = 1;
27
28 $total = 0;
29 $skipped = 0;
30 $errors = 0;
31
32 #$dialect = "ISO";
33 #$dialect = "POSIX";
34 #$dialect = "XPG3";
35 #$dialect = "XPG4";
36 $dialect = "UNIX98";
37
38
39 sub poorfnmatch {
40   my($pattern, $string) = @_;
41   my($strlen) = length ($string);
42   my($res);
43
44   if (substr ($pattern, 0, 1) eq '*') {
45     my($patlen) = length ($pattern) - 1;
46     $res = ($strlen >= $patlen
47             && substr ($pattern, -$patlen, $patlen) eq substr ($string, -$patlen, $patlen));
48   } elsif (substr ($pattern, -1, 1) eq '*') {
49     my($patlen) = length ($pattern) - 1;
50     $res = ($strlen >= $patlen
51             && substr ($pattern, 0, $patlen) eq substr ($string, 0, $patlen));
52   } else {
53     $res = $pattern eq $string;
54   }
55   return $res;
56 }
57
58
59 sub compiletest
60 {
61   my($fnamebase, $msg, $errmsg, $skip) = @_;
62   my($result) = $skip;
63   my($printlog) = 0;
64
65   ++$total;
66   printf ("  $msg...");
67
68   if ($skip != 0) {
69     ++$skipped;
70     printf (" SKIP\n");
71   } else {
72     $ret = system "$CC $CFLAGS -c $fnamebase.c -o $fnamebase.o > $fnamebase.out 2>&1";
73     if ($ret != 0) {
74       printf (" FAIL\n");
75       if ($verbose != 0) {
76         printf ("    $errmsg  Compiler message:\n");
77         $printlog = 1;
78       }
79       ++$errors;
80       $result = 1;
81     } else {
82       printf (" OK\n");
83       if ($verbose > 1 && -s "$fnamebase.out") {
84         # We print all warnings issued.
85         $printlog = 1;
86       }
87     }
88     if ($printlog != 0) {
89       printf ("    " . "-" x 71 . "\n");
90       open (MESSAGE, "< $fnamebase.out");
91       while (<MESSAGE>) {
92         printf ("    %s", $_);
93       }
94       close (MESSAGE);
95       printf ("    " . "-" x 71 . "\n");
96     }
97   }
98   unlink "$fnamebase.c";
99   unlink "$fnamebase.o";
100   unlink "$fnamebase.out";
101
102   $result;
103 }
104
105
106 sub runtest
107 {
108   my($fnamebase, $msg, $errmsg, $skip) = @_;
109   my($result) = $skip;
110   my($printlog) = 0;
111
112   ++$total;
113   printf ("  $msg...");
114
115   if ($skip != 0) {
116     ++$skipped;
117     printf (" SKIP\n");
118   } else {
119     $ret = system "$CC $CFLAGS -o $fnamebase $fnamebase.c > $fnamebase.out 2>&1";
120     if ($ret != 0) {
121       printf (" FAIL\n");
122       if ($verbose != 0) {
123         printf ("    $errmsg  Compiler message:\n");
124         $printlog = 1;
125       }
126       ++$errors;
127       $result = 1;
128     } else {
129       # Now run the program.  If the exit code is not zero something is wrong.
130       $result = system "$fnamebase > $fnamebase.out2 2>&1";
131       if ($result == 0) {
132         printf (" OK\n");
133         if ($verbose > 1 && -s "$fnamebase.out") {
134           # We print all warnings issued.
135           $printlog = 1;
136           system "cat $fnamebase.out2 >> $fnamebase.out";
137         }
138       } else {
139         printf (" FAIL\n");
140         $printlog = 1;
141         unlink "$fnamebase.out";
142         rename "$fnamebase.out2", "$fnamebase.out";
143       }
144     }
145     if ($printlog != 0) {
146       printf ("    " . "-" x 71 . "\n");
147       open (MESSAGE, "< $fnamebase.out");
148       while (<MESSAGE>) {
149         printf ("    %s", $_);
150       }
151       close (MESSAGE);
152       printf ("    " . "-" x 71 . "\n");
153     }
154   }
155   unlink "$fnamebase";
156   unlink "$fnamebase.c";
157   unlink "$fnamebase.o";
158   unlink "$fnamebase.out";
159   unlink "$fnamebase.out2";
160
161   $result;
162 }
163
164
165 sub newtoken {
166   my($token, $nerrors, @allow) = @_;
167   my($idx);
168
169   for ($idx = 0; $idx <= $#allow; ++$idx) {
170     if ($token =~ /^[0-9_]/ || $iskeyword{$token} || poorfnmatch ($allow[$idx], $token)) {
171       return $nerrors;
172     }
173   }
174
175   ++$nerrors;
176   if ($nerrors == 1) {
177     printf ("FAIL\n    " . "-" x 72 . "\n");
178   }
179   printf ("    Namespace violation: \"%s\"\n", $token);
180   return $nerrors;
181 }
182
183
184 sub checknamespace {
185   my($h, $fnamebase, @allow) = @_;
186   my($nerrors) = 0;
187
188   ++$total;
189
190   # Generate a program to get the contents of this header.
191   open (TESTFILE, ">$fnamebase.c");
192   print TESTFILE "#include <$h>\n";
193   close (TESTFILE);
194
195   open (CONTENT, "$CC $CFLAGS -E $fnamebase.c -Wp,-dN | sed -e '/^# [1-9]/d' -e '/^[[:space:]]*\$/d' |");
196   while (<CONTENT>) {
197     chop;
198     if (/^#define (.*)/) {
199       $nerrors = newtoken ($1, $nerrors, @allow);
200     } else {
201       # We have to tokenize the line.
202       my($str) = $_;
203       my($index) = 0;
204       my($len) = length ($str);
205
206       foreach $token (split(/[^a-zA-Z0-9_]/, $str)) {
207         if ($token ne "") {
208           $nerrors = newtoken ($token, $nerrors, @allow);
209         }
210       }
211     }
212   }
213   close (CONTENT);
214   unlink "$fnamebase.c";
215   if ($nerrors != 0) {
216     printf ("    " . "-" x 72 . "\n");
217     ++$errors;
218   } else {
219     printf ("OK\n");
220   }
221 }
222
223
224 while ($#headers >= 0) {
225   my($h) = pop (@headers);
226   my($fnamebase) = "$tmpdir/$h-test";
227   my($missing);
228   my(@allow) = ();
229
230   printf ("Testing <$h>\n");
231   printf ("----------" . "-" x length ($h) . "\n");
232
233   # Generate a program to test for the availability of this header.
234   open (TESTFILE, ">$fnamebase.c");
235   print TESTFILE "#include <$h>\n";
236   close (TESTFILE);
237
238   $missing = compiletest ($fnamebase, "Checking whether <$h> is available",
239                           "Header <$h> not available", 0);
240
241   printf ("\n");
242
243   open (CONTROL, "$CC -E -D$dialect - < data/$h-data |");
244   control: while (<CONTROL>) {
245     chop;
246     next control if (/^#/);
247     next control if (/^[        ]*$/);
248
249     if (/^element *({([^}]*)}|([^ ]*)) *({([^}]*)}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) {
250       my($struct) = "$2$3";
251       my($type) = "$5$6";
252       my($member) = "$7";
253       my($rest) = "$8";
254       my($res) = $missing;
255
256       # Remember that this name is allowed.
257       push @allow, $member;
258
259       # Generate a program to test for the availability of this member.
260       open (TESTFILE, ">$fnamebase.c");
261       print TESTFILE "#include <$h>\n";
262       print TESTFILE "$struct a;\n";
263       print TESTFILE "$struct b;\n";
264       print TESTFILE "extern void xyzzy (__typeof__ (&b.$member), __typeof__ (&a.$member), unsigned);\n";
265       print TESTFILE "void foobarbaz (void) {\n";
266       print TESTFILE "  xyzzy (&a.$member, &b.$member, sizeof (a.$member));\n";
267       print TESTFILE "}\n";
268       close (TESTFILE);
269
270       $res = compiletest ($fnamebase, "Testing for member $member",
271                           "Member \"$member\" not available.", $res);
272
273
274       # Test the types of the members.
275       open (TESTFILE, ">$fnamebase.c");
276       print TESTFILE "#include <$h>\n";
277       print TESTFILE "$struct a;\n";
278       print TESTFILE "extern $type b$rest;\n";
279       print TESTFILE "extern __typeof__ (a.$member) b;\n";
280       close (TESTFILE);
281
282       compiletest ($fnamebase, "Testing for type of member $member",
283                    "Member \"$member\" does not have the correct type.", $res);
284     } elsif (/^constant *([a-zA-Z0-9_]*) *([A-Za-z0-9_]*)?/) {
285       my($const) = $1;
286       my($value) = $2;
287       my($res) = $missing;
288
289       # Remember that this name is allowed.
290       push @allow, $const;
291
292       # Generate a program to test for the availability of this constant.
293       open (TESTFILE, ">$fnamebase.c");
294       print TESTFILE "#include <$h>\n";
295       print TESTFILE "__typeof__ ($const) a = $const;\n";
296       close (TESTFILE);
297
298       $res = compiletest ($fnamebase, "Testing for constant $const",
299                           "Constant \"$const\" not available.", $res);
300
301       if ($value ne "") {
302         # Generate a program to test for the value of this constant.
303         open (TESTFILE, ">$fnamebase.c");
304         print TESTFILE "#include <$h>\n";
305         print TESTFILE "int main (void) { return $const != $value; }\n";
306         close (TESTFILE);
307
308         $res = runtest ($fnamebase, "Testing for value of constant $const",
309                         "Constant \"$const\" has not the right value.", $res);
310       }
311     } elsif (/^type *({([^}]*)|([a-zA-Z0-9_]*))/) {
312       my($type) = "$2$3";
313
314       # Remember that this name is allowed.
315       if ($type =~ /^struct *(.*)/) {
316         push @allow, $1;
317       } elsif ($type =~ /^union *(.*)/) {
318         push @allow, $1;
319       } else {
320         push @allow, $type;
321       }
322
323       # Remember that this name is allowed.
324       push @allow, $type;
325
326       # Generate a program to test for the availability of this constant.
327       open (TESTFILE, ">$fnamebase.c");
328       print TESTFILE "#include <$h>\n";
329       print TESTFILE "$type *a;\n";
330       close (TESTFILE);
331
332       compiletest ($fnamebase, "Testing for type $type",
333                    "Type \"$type\" not available.", $missing);
334     } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(][^)]*[)])/) {
335       my($rettype) = "$2$3";
336       my($fname) = "$4";
337       my($args) = "$5";
338       my($res) = $missing;
339
340       # Remember that this name is allowed.
341       push @allow, $fname;
342
343       # Generate a program to test for availability of this function.
344       open (TESTFILE, ">$fnamebase.c");
345       print TESTFILE "#include <$h>\n";
346       # print TESTFILE "#undef $fname\n";
347       print TESTFILE "$rettype (*foobarbaz) $args = $fname;\n";
348       close (TESTFILE);
349
350       $res = compiletest ($fnamebase, "Test availability of function $fname",
351                           "Function \"$fname\" is not available.", $res);
352
353       # Generate a program to test for the type of this function.
354       open (TESTFILE, ">$fnamebase.c");
355       print TESTFILE "#include <$h>\n";
356       # print TESTFILE "#undef $fname\n";
357       print TESTFILE "extern $rettype (*foobarbaz) $args;\n";
358       print TESTFILE "extern __typeof__ (&$fname) foobarbaz;\n";
359       close (TESTFILE);
360
361       compiletest ($fnamebase, "Test for type of function $fname",
362                    "Function \"$fname\" has incorrect type.", $res);
363     } elsif (/^macro *([^       ]*)/) {
364       my($macro) = "$1";
365
366       # Remember that this name is allowed.
367       push @allow, $macro;
368
369       # Generate a program to test for availability of this macro.
370       open (TESTFILE, ">$fnamebase.c");
371       print TESTFILE "#include <$h>\n";
372       print TESTFILE "#ifndef $macro\n";
373       print TESTFILE "# error \"Macro $macro not defined\"\n";
374       print TESTFILE "#endif\n";
375       close (TESTFILE);
376
377       compiletest ($fnamebase, "Test availability of macro $macro",
378                    "Macro \"$macro\" is not available.", $missing);
379     } elsif (/^allow *(.*)/) {
380       my($pattern) = $1;
381       push @allow, $pattern;
382       next control;
383     } else {
384       # printf ("line is `%s'\n", $_);
385       next control;
386     }
387
388     printf ("\n");
389   }
390   close (CONTROL);
391
392   # Now check the namespace.
393   printf ("  Checking the namespace of \"%s\"... ", $h);
394   if ($missing) {
395     ++$skipped;
396     printf ("SKIP\n");
397   } else {
398     checknamespace ($h, $fnamebase, @allow);
399   }
400
401   printf ("\n\n");
402 }
403
404 printf "-" x 76 . "\n";
405 printf ("  Total number of tests  : %4d\n", $total);
406 printf ("  Number of failed tests : %4d (%3d%%)\n", $errors, ($errors * 100) / $total);
407 printf ("  Number of skipped tests: %4d (%3d%%)\n", $skipped, ($skipped * 100) / $total);
408
409 exit $errors != 0;