aboutsummaryrefslogtreecommitdiffstats
path: root/lib/checksrc.pl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/checksrc.pl')
-rwxr-xr-xlib/checksrc.pl118
1 files changed, 113 insertions, 5 deletions
diff --git a/lib/checksrc.pl b/lib/checksrc.pl
index 15e9aff8..965f0bab 100755
--- a/lib/checksrc.pl
+++ b/lib/checksrc.pl
@@ -35,6 +35,7 @@ my $suppressed; # whitelisted problems
my $file;
my $dir=".";
my $wlist="";
+my @alist;
my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin';
my $verbose;
my %whitelist;
@@ -44,6 +45,10 @@ my %ignore_set;
my %ignore_used;
my @ignore_line;
+my %warnings_extended = (
+ 'COPYRIGHTYEAR' => 'copyright year incorrect',
+ );
+
my %warnings = (
'LONGLINE' => "Line longer than $max_column",
'TABS' => 'TAB characters not allowed',
@@ -74,6 +79,7 @@ my %warnings = (
'SEMINOSPACE' => 'semicolon without following space',
'MULTISPACE' => 'multiple spaces used when not suitable',
'SIZEOFNOPAREN' => 'use of sizeof without parentheses',
+ 'SNPRINTF' => 'use of snprintf',
);
sub readwhitelist {
@@ -86,6 +92,35 @@ sub readwhitelist {
close(W);
}
+# Reads the .checksrc in $dir for any extended warnings to enable locally.
+# Currently there is no support for disabling warnings from the standard set,
+# and since that's already handled via !checksrc! commands there is probably
+# little use to add it.
+sub readlocalfile {
+ my $i = 0;
+
+ open(my $rcfile, "<", "$dir/.checksrc") or return;
+
+ while(<$rcfile>) {
+ $i++;
+
+ # Lines starting with '#' are considered comments
+ if (/^\s*(#.*)/) {
+ next;
+ }
+ elsif (/^\s*enable ([A-Z]+)$/) {
+ if(!defined($warnings_extended{$1})) {
+ print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
+ next;
+ }
+ $warnings{$1} = $warnings_extended{$1};
+ }
+ else {
+ die "Invalid format in $dir/.checksrc on line $i\n";
+ }
+ }
+}
+
sub checkwarn {
my ($name, $num, $col, $file, $line, $msg, $error) = @_;
@@ -153,6 +188,11 @@ while(1) {
$file = shift @ARGV;
next;
}
+ elsif($file =~ /-A(.+)/) {
+ push @alist, $1;
+ $file = shift @ARGV;
+ next;
+ }
elsif($file =~ /-i([1-9])/) {
$indent = $1 + 0;
$file = shift @ARGV;
@@ -174,6 +214,7 @@ while(1) {
if(!$file) {
print "checksrc.pl [option] <file1> [file2] ...\n";
print " Options:\n";
+ print " -A[rule] Accept this violation, can be used multiple times\n";
print " -D[DIR] Directory to prepend file names\n";
print " -h Show help output\n";
print " -W[file] Whitelist the given file - ignore all its flaws\n";
@@ -187,6 +228,7 @@ if(!$file) {
}
readwhitelist();
+readlocalfile();
do {
if("$wlist" !~ / $file /) {
@@ -198,6 +240,17 @@ do {
} while($file);
+sub accept_violations {
+ for my $r (@alist) {
+ if(!$warnings{$r}) {
+ print "'$r' is not a warning to accept!\n";
+ exit;
+ }
+ $ignore{$r}=999999;
+ $ignore_used{$r}=0;
+ }
+}
+
sub checksrc_clear {
undef %ignore;
undef %ignore_set;
@@ -295,8 +348,9 @@ sub scanfile {
open(R, "<$file") || die "failed to open $file";
my $incomment=0;
- my $copyright=0;
+ my @copyright=();
checksrc_clear(); # for file based ignores
+ accept_violations();
while(<R>) {
$windows_os ? $_ =~ s/\r?\n$// : chomp;
@@ -310,9 +364,16 @@ sub scanfile {
checksrc($cmd, $line, $file, $l)
}
- # check for a copyright statement
- if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) {
- $copyright=1;
+ # check for a copyright statement and save the years
+ if($l =~ /\* +copyright .* \d\d\d\d/i) {
+ while($l =~ /([\d]{4})/g) {
+ push @copyright, {
+ year => $1,
+ line => $line,
+ col => index($l, $1),
+ code => $l
+ };
+ }
}
# detect long lines
@@ -511,6 +572,13 @@ sub scanfile {
"use of $2 is banned");
}
+ # scan for use of snprintf for curl-internals reasons
+ if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) {
+ checkwarn("SNPRINTF",
+ $line, length($1), $file, $ol,
+ "use of $2 is banned");
+ }
+
# scan for use of non-binary fopen without the macro
if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) {
my $mode = $2;
@@ -623,9 +691,49 @@ sub scanfile {
$prevl = $ol;
}
- if(!$copyright) {
+ if(!scalar(@copyright)) {
checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1);
}
+
+ # COPYRIGHTYEAR is a extended warning so we must first see if it has been
+ # enabled in .checksrc
+ if(defined($warnings{"COPYRIGHTYEAR"})) {
+ # The check for updated copyrightyear is overly complicated in order to
+ # not punish current hacking for past sins. The copyright years are
+ # right now a bit behind, so enforcing copyright year checking on all
+ # files would cause hundreds of errors. Instead we only look at files
+ # which are tracked in the Git repo and edited in the workdir, or
+ # committed locally on the branch without being in upstream master.
+ #
+ # The simple and naive test is to simply check for the current year,
+ # but updating the year even without an edit is against project policy
+ # (and it would fail every file on January 1st).
+ #
+ # A rather more interesting, and correct, check would be to not test
+ # only locally committed files but inspect all files wrt the year of
+ # their last commit. Removing the `git rev-list origin/master..HEAD`
+ # condition below will enfore copyright year checks against the year
+ # the file was last committed (and thus edited to some degree).
+ my $commityear = undef;
+ @copyright = sort {$$b{year} cmp $$a{year}} @copyright;
+
+ if(`git status -s -- $file` =~ /^ [MARCU]/) {
+ $commityear = (localtime(time))[5] + 1900;
+ }
+ elsif (`git rev-list --count origin/master..HEAD -- $file` !~ /^0/) {
+ my $grl = `git rev-list --max-count=1 --timestamp HEAD -- $file`;
+ $commityear = (localtime((split(/ /, $grl))[0]))[5] + 1900;
+ }
+
+ if(defined($commityear) && scalar(@copyright) &&
+ $copyright[0]{year} != $commityear) {
+ checkwarn("COPYRIGHTYEAR", $copyright[0]{line}, $copyright[0]{col},
+ $file, $copyright[0]{code},
+ "Copyright year out of date, should be $commityear, " .
+ "is $copyright[0]{year}", 1);
+ }
+ }
+
if($incomment) {
checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1);
}