2 # Copyright (C) 2006-2009, Parrot Foundation.
8 use lib qw( . lib ../lib ../../lib );
9 use Test::More tests => 5;
10 use Parrot::Distribution;
14 t/codingstd/c_header_guards.t - checks for rules related to guards in C header files
19 % prove t/codingstd/c_header_guards.t
22 % perl t/codingstd/c_header_guards.t include/parrot/bar.h
26 Checks that all C language header files have an
27 #ifndef PARROT_WHATEVER_H_GUARD definition, then they
28 #define PARROT_WHATEVER_H_GUARD and add an
29 #endif /* PARROT_WHATEVER_H_GUARD */ at the end, of the file as specified
34 Mark Glines <mark at glines dot org>
38 L<docs/pdds/pdd07_codingstd.pod>
42 my $DIST = Parrot::Distribution->new();
48 my %files = map { $_->path() => 1 } $DIST->c_header_files();
49 my $href = $DIST->generated_files();
51 foreach my $file ( keys %$href ) {
52 if ( $file =~ /\.h$/ ) {
53 $files{$file} = 1 if -f $file;
57 # not all files should be subject to the coding standards
58 foreach my $file ( keys %files ) {
59 delete $files{$file} if $DIST->is_c_exemption($file);
62 @files = sort keys %files;
65 check_header_guards(@files);
69 sub check_header_guards {
70 my ( %guardnames, %redundants, %collisions, %missing_guard, %missing_define, %missing_comment );
72 F: foreach my $file (@_) {
73 open my $fh, '<', $file
74 or die "Cannot open '$file' for reading!\n";
79 my ( $ifndef, $define, $endif );
80 L: foreach my $line (@source) {
84 # skip Bison parser files
85 next F if $line =~ /A Bison parser/;
87 # skip the non-preprocessor lines
88 next L unless substr( $line, 0, 1 ) eq '#';
90 # skip the "#", and any leading whitespace
91 $line = substr( $line, 1 );
94 if ( $line =~ m{ifndef (PARROT_.+_GUARD)$} ) {
96 # allow include/parrot/platform.h to have redundant guards;
97 # it contains verbatim copies of other header files (which
98 # have their own guards).
99 next L if ( defined($ifndef) && $ifndef eq 'PARROT_PLATFORM_H_GUARD' );
101 # check for multiple guards in the same file
102 $redundants{$file} = $1 if defined $ifndef;
104 # check for the same guard-name in multiple files
105 if ( exists( $guardnames{$1} ) ) {
106 if ( !duplicate_files( $file, $guardnames{$1} ) ) {
107 $collisions{$file} = $guardnames{$1};
112 $guardnames{$1} = $file;
115 if ( $line =~ m{define (PARROT_.+_GUARD)$} ) {
117 if ( defined($ifndef) && $ifndef eq $1 );
120 if ( $line =~ m{endif /\* (PARROT_.+_GUARD) \*/$} ) {
122 if ( defined($ifndef) && $ifndef eq $1 );
126 $missing_guard{$file} = 1 unless defined $ifndef;
127 $missing_define{$file} = 1 unless defined $define;
128 $missing_comment{$file} = 1 unless defined $endif;
131 ok( !%collisions, "identical PARROT_*_GUARD macro names used in headers" )
132 or diag( "collisions: \n" . join( ", \n", %collisions ) );
134 ok( !%redundants, "multiple PARROT_*_GUARD macros found in headers" )
135 or diag( "redundants: \n" . join( ", \n", keys %redundants ) );
138 "missing or misspelled PARROT_*_GUARD ifndef in headers" )
139 or diag( "missing guard: \n"
140 . join( ", \n", sort keys %missing_guard )
141 . "\nyou need to add a line like:\n"
142 . " #ifndef PARROT_*_GUARD\n"
143 . "at the top of the header." );
145 ok( !%missing_define,
146 "missing or misspelled PARROT_*_GUARD define in headers" )
147 or diag( "missing define: \n"
148 . join( ", \n", sort keys %missing_define )
149 . "\nyou need to add a line like:\n"
150 . " #define PARROT_*_GUARD\n"
151 . "at the top of the header." );
153 ok( !%missing_comment, "missing or misspelled PARROT_*_GUARD "
154 . "comment after the endif in headers" )
155 or diag( "missing endif comment: \n"
156 . join( ", \n", sort keys %missing_comment )
157 . "\nyou need to add a line like:\n"
158 . " #endif /* PARROT_*_GUARD */\n"
159 . "at the end of the header." );
164 sub duplicate_files {
165 my ( $file1, $file2 ) = @_;
166 open my $fh1, '<', $file1
167 or die "Cannot open '$file1' for reading!\n";
168 open my $fh2, '<', $file2
169 or die "Cannot open '$file2' for reading!\n";
173 return $file1 eq $file2;
178 # cperl-indent-level: 4
181 # vim: expandtab shiftwidth=4: