1#!/usr/bin/perl -w
2# collate-test: Collate testcases from several source files.
3#
4# Copyright (C) 2007,2008,2011,2015 Olly Betts
5# Copyright (C) 2008 Lemur Consulting Ltd
6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License as
9# published by the Free Software Foundation; either version 2 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20
21use strict;
22
23my $generated_warning =
24"/* Warning: This file is generated by $0 - do not modify directly! */\n";
25
26my %by_cond = ();
27my $srcdir = shift @ARGV;
28my $collated_hdr = shift @ARGV;
29my $allfile = shift @ARGV;
30
31open COLLATED_HDR, ">$collated_hdr.tmp" or die $!;
32print COLLATED_HDR "$generated_warning\n";
33
34open ALL, ">$allfile.tmp" or die $!;
35print ALL $generated_warning;
36
37for my $cc_source (@ARGV) {
38    (my $generated_h = $cc_source) =~ s/\.\w+$/\.h/;
39    print ALL "#include \"$generated_h\"\n";
40
41    -f $cc_source or $cc_source = "$srcdir/$cc_source";
42
43    open HDR, ">$generated_h.tmp" or die $!;
44    print HDR $generated_warning;
45    open SRC, "<$cc_source" or die $!;
46    my $ignore = 0;
47    my @if_stack;
48    while (<SRC>) {
49	if (!$ignore && /^DEFINE_TESTCASE\((.*?),\s*(.*)\)/) {
50	    my ($test_func, $cond) = ($1, $2);
51	    $cond =~ s/\s+//g;
52	    push @{$by_cond{$cond}}, $test_func;
53	    print HDR "extern void test_$test_func();\n";
54	}
55        if (s/^#\s*//) {
56	    s!/\*.*?\*/! !g;
57	    s!//.*!!;
58	    if (/^if\s*0\s*$/) {
59		push @if_stack, $ignore;
60	        $ignore = 1;
61	    } elsif (/^if/) {
62		push @if_stack, $ignore;
63	    } elsif (/^endif/) {
64		$ignore = pop @if_stack;
65	    }
66	}
67    }
68    close SRC;
69    close HDR or die $!;
70    update_if_required($generated_h);
71}
72
73foreach my $cond (sort keys %by_cond) {
74#	my $name = $cond;
75#	$name =~ s/\&\&/_and_/g;
76#	$name =~ s/\|\|/_or_/g;
77#	$name =~ s/\!/not_/g;
78#	$name =~ s/\(/bra_/g;
79#	$name =~ s/\)/_ket/g;
80    my $c_cond = $cond;
81    $c_cond =~ s/\b([a-z]+)\b/(properties&\U$1\E)/g;
82    print COLLATED_HDR <<END;
83    if ($c_cond) {
84	static const test_desc tests[] = {
85END
86    for (@{$by_cond{$cond}}) {
87	print COLLATED_HDR <<END;
88	    { \"$_\", test_$_ },
89END
90    }
91    print COLLATED_HDR <<END;
92	    { 0, 0 }
93	};
94	result = max(result, test_driver::run(tests));
95    }
96END
97}
98
99close ALL or die $!;
100update_if_required($allfile);
101
102close COLLATED_HDR or die $!;
103update_if_required($collated_hdr);
104
105# If $file.tmp is different to $file, rename it over the top.  Otherwise
106# just delete it to avoid needlessly updating $file's timestamp.
107sub update_if_required {
108    my $file = shift;
109    my $current_size = -s $file;
110    if (defined $current_size && $current_size == -s "$file.tmp") {
111	open OLD, "<$file" or die $!;
112	open NEW, "<$file.tmp" or die $!;
113	my $different = 0;
114	while (<OLD>) {
115	    my $new = <NEW>;
116	    if ($_ ne $new) {
117		$different = 1;
118		last;
119	    }
120	}
121	close OLD;
122	close NEW;
123	if (! $different) {
124	    unlink "$file.tmp";
125	    return;
126	}
127    }
128different:
129    unlink $file if $^O eq 'MSWin32' && defined $current_size;
130    rename "$file.tmp", $file or dir $!;
131}
132