You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
9.2 KiB
352 lines
9.2 KiB
@rem = '
|
|
@perl.exe %~f0 %*
|
|
@goto :EOF
|
|
'; undef @rem;
|
|
|
|
#
|
|
# This script verifies adherence to the style document
|
|
#
|
|
|
|
# Include 'spelling.pl' from the same directory as this script
|
|
$dir=$0; $dir =~ s/\\[^\\]*$//;
|
|
require "$dir\\spelling.pl";
|
|
|
|
# List of error classes to keep quiet about
|
|
# Options: (spell_c, indent, line_length, tabs, braces, eof)
|
|
@suppress_errors = (spell_c);
|
|
foreach $t (@suppress_errors) { $suppress_errors{$t} = 1; }
|
|
|
|
# Process command-line options
|
|
@args=@ARGV;
|
|
undef @ARGV;
|
|
|
|
$syntax = "style [-?] [<file> ...]";
|
|
|
|
for ($i=0;$i<=$#args;$i++) {
|
|
$_ = $args[$i];
|
|
if (0) {
|
|
} elsif (/^[-\/]\w$/) {
|
|
$writeSpellingErrors = 1;
|
|
} elsif (/^[-\/]\?$/) {
|
|
print <<EOT;
|
|
$syntax
|
|
|
|
Checks adherence to the style document.
|
|
|
|
-w Writes misspelt words in comments to spelling.err
|
|
EOT
|
|
|
|
exit 0;
|
|
} else {
|
|
push (@ARGV,$_);
|
|
}
|
|
}
|
|
|
|
if ($#ARGV>=0) {
|
|
@filespecs = @ARGV;
|
|
}
|
|
|
|
# Supply a default file set if none given
|
|
@exts = ("cpp", "cxx", "c", "h", "hxx", "hpp");
|
|
if ($#filespecs<0) { @filespecs = map("*.$_", @exts); }
|
|
|
|
# Subroutines
|
|
|
|
# Report a file-wide error
|
|
sub fileError {
|
|
local ($type, $string) = @_;
|
|
return if $suppress_errors{$type};
|
|
print "$filename: $string\n";
|
|
}
|
|
|
|
# Report an error at a given line
|
|
sub lineError {
|
|
local ($type, $string) = @_;
|
|
return if $suppress_errors{$type};
|
|
print "$filename($line): $string\n";
|
|
}
|
|
|
|
# Spellcheck a comment
|
|
sub checkComment {
|
|
local ($_) = @_;
|
|
|
|
while (/([a-zA-Z_0-9']*)/g) {
|
|
my $word=$1;
|
|
|
|
# Skip numbers
|
|
next if ($word =~ /^[0-9]*[Ll]?$/);
|
|
next if ($word =~ /^0[Xx][0-9a-fA-F]+[lL]?$/);
|
|
|
|
# Skip words 3 or fewer letters long, containing digits
|
|
next if ($word =~ /[0-9]/ && length($word)<=3);
|
|
|
|
# Remove leading/trailing hyphens
|
|
$word =~ s/^'//g;
|
|
$word =~ s/'$//g;
|
|
next if !$word;
|
|
|
|
# Try an exact match against the English dictionary
|
|
next if $dic_english{$word};
|
|
|
|
# Try the code dictionary
|
|
next if $dic_code{$word};
|
|
|
|
# Check for shifty words
|
|
if ($dic_shifty{$word}) {
|
|
&lineError("spell_c", "Shifty word: \"$word\"");
|
|
next;
|
|
}
|
|
|
|
# If it's capitalized, or all caps, look for the lowercase
|
|
# version in the English dictionary
|
|
if ($word =~ /^([A-Z])([^A-Z]*)$/) {
|
|
my $i = $1;
|
|
$i =~ tr/A-Z/a-z/;
|
|
next if $dic_english{"$i$2"};
|
|
} elsif ($word !~ /[a-z]/) {
|
|
$word =~ tr/A-Z/a-z/;
|
|
next if $dic_english{"$i$2"};
|
|
}
|
|
|
|
# Okay, it's a spelling error
|
|
|
|
if ($writeSpellingErrors) {
|
|
# Put it in the English error list if it's not recognizably an
|
|
# identifier
|
|
if (($word !~ /^.+[A-Z0-9]/) && ($word !~ /_/)) {
|
|
push (@errors_english, $word);
|
|
} else {
|
|
push (@errors_code, $word);
|
|
}
|
|
} else {
|
|
&lineError("spell_c", "Misspelt word: \"$word\"");
|
|
}
|
|
}
|
|
}
|
|
|
|
&loadDictionaries() unless $suppress_errors{spell_c};
|
|
|
|
# Check the indentation level
|
|
#
|
|
# Uses $lastIndentErrorLine and $actualIndent
|
|
sub checkIndent {
|
|
my $pos;
|
|
foreach $pos (@_) {
|
|
if ($pos == $actualIndent) {
|
|
return 1;
|
|
}
|
|
}
|
|
if ($line != $lastIndentErrorLine) {
|
|
&lineError("indent", "Indentation error: Actual pos $actualIndent, expected ".
|
|
join(', ', grep($_ != -1, @_)));
|
|
$lastIndentErrorLine = $line;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub currentIndent {
|
|
$mainIndentPos[$#mainIndentPos];
|
|
}
|
|
|
|
# Evil function which references these global variables:
|
|
# FILE, $line, $altindentpos, $lineAccum, $commentAccum, $tempindentpos
|
|
sub getLine {
|
|
local $_;
|
|
|
|
LINE:
|
|
{
|
|
$_ = <FILE>;
|
|
defined($_) || last;
|
|
|
|
chop;
|
|
|
|
$line++;
|
|
|
|
# Check line length
|
|
/^(.*)$/;
|
|
my $l = length($1);
|
|
if ($l > 80) {
|
|
&lineError("line_length", "Line too long");
|
|
}
|
|
|
|
# Accumulate lines which have escaped newlines
|
|
if (/\\$/) {
|
|
$lineAccum .= $_;
|
|
redo LINE;
|
|
} elsif (defined ($lineAccum)) {
|
|
$lineAccum .= $_;
|
|
$_ = $lineAccum;
|
|
$lineAccum = undef;
|
|
}
|
|
|
|
COMMENTLOOP:
|
|
{
|
|
# Accumulate comments
|
|
if (defined($commentAccum)) {
|
|
if (s;^(.*?)\*/;;) {
|
|
# End of multi-line comment
|
|
$commentAccum .= " $1";
|
|
&checkComment($commentAccum);
|
|
$commentAccum = undef;
|
|
} else {
|
|
# Inside multi-line comment
|
|
$commentAccum .= " $_";
|
|
redo LINE;
|
|
}
|
|
}
|
|
if ((s;//(.*)$;;) || (s;/\*(.*?)\*/;;)) {
|
|
# Single-line comment - either // or /* ... */
|
|
&checkComment($1);
|
|
redo COMMENTLOOP;
|
|
}
|
|
if (s;/\*(.*)$;;) {
|
|
# Start of multi-line comment
|
|
$commentAccum = $1;
|
|
}
|
|
}
|
|
|
|
# Skip blank lines
|
|
redo LINE if /^\s*$/;
|
|
|
|
# No tabs allowed
|
|
if (s/\t/ /g) {
|
|
&lineError("tabs", "Line contains tab characters");
|
|
}
|
|
|
|
#
|
|
# Indentation checking
|
|
#
|
|
/^( *)[^ ]/;
|
|
local $actualIndent = length($1);
|
|
|
|
# Was the previous line #if* ?
|
|
if ($prevLineHashIf) {
|
|
$prevLineHashIf = 0;
|
|
&checkIndent(¤tIndent, ¤tIndent+4);
|
|
push(@mainIndentPos, $actualIndent);
|
|
}
|
|
|
|
# #if*, #endif
|
|
if (/^ *#if/ || /^ *#endif/) {
|
|
if (/^ *#if/) {
|
|
$prevLineHashIf = 1;
|
|
} else {
|
|
pop(@mainIndentPos);
|
|
}
|
|
&checkIndent(¤tIndent);
|
|
redo LINE;
|
|
}
|
|
|
|
# #else
|
|
if (/^ *#else/) {
|
|
&checkIndent($mainIndentPos[$#mainIndentPos-1]);
|
|
redo LINE;
|
|
}
|
|
|
|
# Process braces.
|
|
my $braceDelta = 0;
|
|
while (/{/g) { $braceDelta++; }
|
|
while (/}/g) { $braceDelta--; }
|
|
|
|
if ($braceDelta != 0) {
|
|
# Check for braces not on their own lines (except for matched braces)
|
|
if (!/^[\s{};]*$/) {
|
|
&lineError("braces", "Brace should be on separate line");
|
|
}
|
|
if ($braceDelta > 0) {
|
|
&checkIndent(¤tIndent);
|
|
push(@mainIndentPos, $actualIndent+4);
|
|
} else {
|
|
pop(@mainIndentPos);
|
|
&checkIndent(¤tIndent);
|
|
}
|
|
redo LINE;
|
|
}
|
|
|
|
# Certain constructs effectively cause a temporary unindent by one
|
|
# level. These are:
|
|
# "case XYZ:","default:", "public:", "private:",
|
|
# "protected:", and labels.
|
|
if (/case .*:/ || /default:/ || /public:/ || /private:/ ||
|
|
/protected:/ || /^ *[a-zA-Z_0-9]+: *$/) {
|
|
&checkIndent(¤tIndent-4);
|
|
redo LINE;
|
|
}
|
|
|
|
# Test the indent level
|
|
# Hack - for now, $tempindentpos!=-1, we skip the check
|
|
if ($tempIndentPos == -1) {
|
|
&checkIndent(¤tIndent, $altIndentPos, $tempIndentPos);
|
|
}
|
|
|
|
# Multi-line statements may be temporarily indented
|
|
if (($braceDelta == 0) && (!/; *$/)) {
|
|
$tempIndentPos = ¤tIndent+4;
|
|
} else {
|
|
$tempIndentPos = -1;
|
|
}
|
|
}
|
|
|
|
$_;
|
|
}
|
|
|
|
# Evil function which references global variables $token, $ttype, FILE
|
|
sub getToken {
|
|
while (1) {
|
|
if ($parseLine =~ /^\s*$/) {
|
|
$parseLine = &getLine();
|
|
$parseLine || return 0;
|
|
next;
|
|
}
|
|
|
|
# if (/([0-9\.]([0-9e\.]*))\b/g) {
|
|
# }
|
|
# $token = $1;
|
|
|
|
# for now, eat everything
|
|
$parseLine = "";
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
$findstr = "dir /b " . join(" ", @filespecs)." 2>nul";
|
|
|
|
open(FIND, "$findstr|");
|
|
@files = <FIND>;
|
|
close(FIND);
|
|
|
|
# Remove blank lines
|
|
@files = grep(!/^\s*$/, @files);
|
|
|
|
chop @files;
|
|
|
|
$#files >= 0 || die "No files found (".join(", ", @filespecs).").\n";
|
|
|
|
foreach $filename (@files) {
|
|
open(FILE, "$filename");
|
|
|
|
# Remove path from filename
|
|
$filename =~ s/.*\\([^\\]*)/$1/;
|
|
|
|
$line=0;
|
|
$lastIndentErrorLine=0;
|
|
|
|
$tempIndentPos = -1; # Temporary indentation, used for multi-line statements
|
|
@mainIndentPos = (0); # Stack of indent positions
|
|
$prevLineHashIf = 0; # If true, the previous line was a #if
|
|
|
|
$parseLine = "";
|
|
undef $lineAccum;
|
|
undef $commentAccum;
|
|
while (&getToken()) {
|
|
}
|
|
close(FILE);
|
|
if (defined($lineAccum) || defined($commentAccum)) {
|
|
&lineError("eof", "Unexpected EOF");
|
|
}
|
|
}
|
|
|
|
if ($writeSpellingErrors) {
|
|
&writeSpellingErrors("english", "code");
|
|
}
|
|
|