cddlchk.pl revision cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0
#
# See the bottom of the file for the license, and for the reason why it is
# there and not here.
#
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
#
#
# Check source files for a valid CDDL block.
#
use strict;
use warnings;
#
# Global variables.
#
our $CmtChrs = q{#*!/\";.}; # Acceptable comment characters.
our %Opt; # Command-line flags.
our @CDDL; # Approved CDDL block.
our $CDDLStartRE; # RE to match the first line of a CDDL block.
our $CDDLEndRE; # RE to match the last line of a CDDL block.
our $CmtRE; # Comment regular expression.
our %IgnoreDir; # Directories to be ignored.
our %IgnoreFile; # Files to be ignored.
our $IgnoreExtnRE; # File extensions to be ignored.
#
# Print a help message - see Getopt::Std.
#
sub HELP_MESSAGE
{
}
#
# Print a version message - see Getopt::Std.
#
sub VERSION_MESSAGE
{
print($out "cddlchk version $VERSION\n");
}
#
# Print a message.
#
sub message
{
print("Message: ", join("\n ", @_), "\n");
}
#
# Print a warning message.
#
sub warning
{
print("Warning: ", join("\n ", @_), "\n");
}
#
# Print an error message.
#
sub error
{
print("Error: ", join("\n ", @_), "\n");
$Status = 1;
}
#
# Load an exceptions file. $root, if specified, will be prepended to all
# relative file and directory paths. Exceptions may be one of three types:
# 1. File paths.
# 2. Directories, specified with a trailing '/'.
# 3. File extensions, specified with a leading '*.'
# Returns true if the file loaded OK, false otherwise.
#
sub load_exceptions
{
# Fix up the $root prefix, if specified.
# Open the exception file.
my $fh;
return(0);
}
# Zero any existing exceptions, read the file.
%IgnoreDir = ();
%IgnoreFile = ();
$IgnoreExtnRE = undef;
my @ext;
chomp($line);
# File extension.
if ($line =~ m{^\*\.(.*)$}) {
push(@ext, quotemeta($1));
# Directory path.
} elsif (($_) = $line =~ m{^(.*)/$}) {
$_ = "$root$_"
$IgnoreDir{$_} = 1;
# File path.
} else {
$line = "$root$line"
}
}
# Compose the extension exception RE if any were defined.
if (@ext > 0) {
$IgnoreExtnRE = qr{$_};
}
return(close($fh));
}
#
# Check if the specified file or directory should be validated or not.
# $type is 'file' or 'dir'.
#
sub is_exception
{
if ($type eq 'file') {
return(exists($IgnoreFile{$path}) ||
} else {
}
}
#
# Check a file for a valid CDDL block. If $Opt{a} is true an error will be
# reported if the file doesn't contain any CDDL at all, if it is false a
# warning will only be reported if the file has a CDDL block which is invalid.
# If $Opt{v} is true valid files will be listed, otherwise they will not.
#
sub cuddle
{
my ($file) = @_;
# Open the file.
my $fh;
error("Can't open $file: $!");
return;
}
# Extract all the CDDL blocks.
$msg = 0;
$block = [];
while (defined($_ = <$fh>)) {
if (my $s = $_ =~ $CDDLStartRE ... $_ =~ $CDDLEndRE) {
chomp($_);
push(@$block, $_);
# First line of CDDL block.
if ($s == 1) {
$start = $.;
# Last line of CDDL block.
} elsif (substr($s, -2) eq 'E0') {
push(@cddl,
$start = undef;
$block = [];
}
}
}
# Close the file.
if (! close($fh)) {
warning("Can't close $file: $!");
}
# Check for unterminated blocks.
if (defined($start)) {
error("Unterminated CDDL block in file $file",
"at line $start");
$msg++;
}
# Check for no CDDL - may be a warning.
warning("No CDDL block in file $file");
return;
}
# Check for multiple CDDL blocks.
if (@cddl > 1) {
error("Multiple CDDL blocks in file $file",
$msg++;
}
# Validate each CDDL block.
foreach my $c (@cddl) {
# Compare each line.
for (my $i = 0; $i < @CDDL; $i++) {
$_ = $i < @$b ? $b->[$i] : '';
"Invalid line in CDDL block in file $file",
"at line " . ($s + $i) . ", should be",
"'[$CmtChrs ]*$CDDL[$i]'", "is", "'$_'");
$msg++;
last; # Just report the first error.
}
}
}
# Report the file if required.
}
#
# Main.
#
# Check the command-line arguments.
# Read in the exception list.
if (exists($Opt{x})) {
if (! load_exceptions($Opt{x})) {
error("Can't load exceptions file $Opt{x}: $!");
exit(2);
}
}
# Read in the template CDDL block from the end of the file.
while (defined($_ = <DATA>)) {
chomp($_);
push(@CDDL, $_);
}
# File::Find callback.
my $wanted = sub {
} elsif (-f _) {
}
};
# Process each file and directory on the command-line.
if (-f $arg) {
# Explicitly listed files must have a CDDL block.
} elsif (-d $arg) {
} else {
}
}
exit($Status);
#
# Inline documentation.
#
=pod
=head1 NAME
cddlchk - Check for valid CDDL blocks
=head1 SYNOPSIS
cddlchk [B<-avxM> B<--help> B<--version>] [B<<file or directory>>...]
=head1 DESCRIPTION
cddlchk inspects files for missing, obsolete, or corrupt CDDL blocks.
=head1 OPTIONS
The following options are supported:
=over
=item B<-a>
Check that all the specified files have a CDDL block, and report a warning if
they do not. If this flag is not specified, only files containing an existing
CDDL block are validated.
=item B<-v>
Report on all files, not just those with invalid headers.
=item B<-x>
Load an exceptions file containing a list of files, directories and file
extensions to be ignored. Exceptions may be one of three types:
=over
=item * B<File paths>
=item * B<Directories>, specified with a trailing C</>
=item * B<File extensions>, specified with a leading C<*.>
=back
=item B<-M>
Display the manpage for the chkcddl command.
=item B<--help>
Display command-line help for the cddlchk command.
=item B<--version>
Display the program version number.
=back
=head1 EXIT STATUS
The following exit status values are returned:
=over
=item B<0>
The command completed sucessfully. No errors or warnings were reported.
=item B<1>
The command completed unsucessfully. One or more errors or warnings were
reported.
=item B<2>
Invalid command-line arguments were specified to the command, or one of the
command-line help functions was invoked.
=back
=cut
#
# Put the CDDL at the end of the file so we can use it as a template.
#