On Sat, 05 May 2007 07:58:45 -0700
"Bernhard Schmalhofer via RT" <[EMAIL PROTECTED]> wrote:
> > * Fix up the indentation problems caused by the above bullet point.
> > (TODO: why does t/codingstd/c_indent.t require indentation for #if
> > and #ifdef, but not for #ifndef?)
> As far as I understand c_indent.t, #ifndef is also covered

Except that it isn't.  If you apply the attached patch, you will see
that t/codingstd/c_indent.t starts failing.  C_indent.t will not be
happy until you reindent everything else, inside of it.  (This patch
should not be checked in, it only exhibits the problem, it does not
solve anything.)



> > I'd like to write some tests for this stuff, and then fix up the
> > rest of the cases (I know I've missed a bunch).  How would the list
> > feel about a patch to PDD07 specifying the above for header files,
> > and a codingstd test to enforce it?
> My feeling is that we need to differentiate two cases:
> i. header files that define an interfaces for e.g. a subsystem
> ii. Convenience headers, that contain declaration of internal
> functions
> 
> Case i. might need stricter checks than ii.


Thanks for your input.  I have written a test case for this,
t/codingstd/c_header_guards.t (attached), which checks the following:

* The existence of an #ifndef PARROT_*_GUARD
* That each header file only contains one #ifndef PARROT_*_GUARD
* The existence of a matching #define (this caught a few misspells)
* The existence of an #endif /* PARROT_*_GUARD */
* That the PARROT_*_GUARD macro is unique (doesn't stomp on any other
files)

I patched up another large set of headers, to pass this test.  But
before I send in another big patch with some changes to type ii
("convenience") headers, can you please tell me if there's a clean,
programmatic way to determine which headers it should perform strict
checks on?  That way I can fix the test to only run on the
non-"convenience" subset of headers.

Also, should any of the above tests be applied to type ii headers, or
should they only apply to type i headers?  (Should type ii headers be
ignored completely, or only subjected to a subset of the tests?)

 Mark
Index: src/stm/stm_internal.h
===================================================================
--- src/stm/stm_internal.h	(revision 18445)
+++ src/stm/stm_internal.h	(working copy)
@@ -1,4 +1,4 @@
-#ifndef PARROT_STM_INTERNAL_H_GUARD
+#if !defined(PARROT_STM_INTERNAL_H_GUARD)
 #define PARROT_STM_INTERNAL_H_GUARD
 
 #include <parrot/parrot.h>
#! perl
# Copyright (C) 2006-2007, The Perl Foundation.
# $Id$

use strict;
use warnings;

use lib qw( . lib ../lib ../../lib );
use Test::More tests => 5;
use Parrot::Distribution;

=head1 NAME

t/codingstd/c_header_guards.t - checks for rules related to guards in C header files

=head1 SYNOPSIS

    # test all files
    % prove t/codingstd/c_header_guards.t

    # test specific files
    % perl t/codingstd/c_header_guards.t include/parrot/bar.h

=head1 DESCRIPTION

Checks that all C language header files have an #ifndef PARROT_WHATEVER_H_GUARD definition,
and an #endif /* PARROT_WHATEVER_H_GUARD */ at the end, as specified in PDD07.

=head1 SEE ALSO

L<docs/pdds/pdd07_codingstd.pod>

=cut

my $DIST = Parrot::Distribution->new();
my @files = @ARGV ? @ARGV : map { $_->path() } $DIST->c_header_files();

#foreach my $file ( @files ) {
#    print $file, "\n";
#}
#exit;

check_header_guards(@files);

exit;

sub check_header_guards {
    my (%guardnames, %redundants, %collisions,
        %missing_guard, %missing_define, %missing_comment);

F:  foreach my $file (@_) {
        open my $fh, '<', $file
            or die "Can not open '$file' for reading!\n";
        my @source = <$fh>;
        close $fh;
        chomp @source;

        my ($ifndef, $define, $endif);
L:          foreach my $line (@source) {
            $line =~ s/\s+/ /;
            $line =~ s/^ //;

            # skip Bison parser files
            next F if $line =~ /A Bison parser/;

            # skip the non-preprocessor lines
            next L unless substr($line,0,1) eq '#';

            # skip the "#", and any leading whitespace
            $line = substr($line, 1);
            $line =~ s/^ //;

            if($line =~ m[ifndef (PARROT_.+_GUARD)$]) {
                # check for multiple guards in the same file
                $redundants{$file} = $1 if defined $ifndef;
                # check for the same guard-name in multiple files
                $collisions{$file} = $guardnames{$1}
                    if exists $guardnames{1};

                $ifndef = $1;
                $guardnames{$1} = $file;
            }

            if($line =~ m[define (PARROT_.+_GUARD)$]) {
                $define = $1
                    if(defined($ifndef) && $ifndef eq $1);
            }

            if($line =~ m[endif /\* (PARROT_.+_GUARD) \*/$]) {
                $endif = $1
                    if(defined($ifndef) && $ifndef eq $1);
            }
        }
        
        $missing_guard{$file}   = 1 unless defined $ifndef;
        $missing_define{$file}  = 1 unless defined $define;
        $missing_comment{$file} = 1 unless defined $endif;
    }
    ok(!(scalar %collisions),
       "identical PARROT_*_GUARD macro names used in headers "
       . join(", ", %collisions));
    ok(!(scalar %redundants),
       "multiple PARROT_*_GUARD macros found in headers "
       . join(", ", keys %redundants));
    ok(!(scalar %missing_guard),
       "missing or misspelled PARROT_*_GUARD ifndef in headers "
       . join(", ", sort keys %missing_guard));
    ok(!(scalar %missing_define),
       "missing or misspelled PARROT_*_GUARD define in headers "
       . join(", ", sort keys %missing_define));
    ok(!(scalar %missing_comment), 
       "missing or misspelled PARROT_*_GUARD comment after the #endif in headers "
       . join(", ", sort keys %missing_comment));
}
return 0;

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4:

Reply via email to