libcurl: updated to 7.49.1
[tomato.git] / release / src / router / libcurl / lib / checksrc.pl
blobaacb242b5d829543c18efd7610e2d5f75426b478
1 #!/usr/bin/perl
2 #***************************************************************************
3 # _ _ ____ _
4 # Project ___| | | | _ \| |
5 # / __| | | | |_) | |
6 # | (__| |_| | _ <| |___
7 # \___|\___/|_| \_\_____|
9 # Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at https://curl.haxx.se/docs/copyright.html.
15 # You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 # copies of the Software, and permit persons to whom the Software is
17 # furnished to do so, under the terms of the COPYING file.
19 # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 # KIND, either express or implied.
22 ###########################################################################
24 my $max_column = 79;
25 my $indent = 2;
27 my $warnings;
28 my $errors;
29 my $supressed; # whitelisted problems
30 my $file;
31 my $dir=".";
32 my $wlist;
33 my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin';
34 my $verbose;
35 my %whitelist;
37 my %warnings = (
38 'LONGLINE' => "Line longer than $max_column",
39 'TABS' => 'TAB characters not allowed',
40 'TRAILINGSPACE' => 'Trailing white space on the line',
41 'CPPCOMMENTS' => '// comment detected',
42 'SPACEBEFOREPAREN' => 'space before an open parenthesis',
43 'SPACEAFTERPAREN' => 'space after open parenthesis',
44 'SPACEBEFORECLOSE' => 'space before a close parenthesis',
45 'SPACEBEFORECOMMA' => 'space before a comma',
46 'RETURNNOSPACE' => 'return without space',
47 'COMMANOSPACE' => 'comma without following space',
48 'BRACEELSE' => '} else on the same line',
49 'PARENBRACE' => '){ without sufficient space',
50 'SPACESEMILCOLON' => 'space before semicolon',
51 'BANNEDFUNC' => 'a banned function was used',
52 'FOPENMODE' => 'fopen needs a macro for the mode string',
53 'BRACEPOS' => 'wrong position for an open brace',
54 'INDENTATION' => 'wrong start column for code',
55 'COPYRIGHT' => 'file missing a copyright statement',
56 'BADCOMMAND' => 'bad !checksrc! instruction',
57 'UNUSEDIGNORE' => 'a warning ignore was not used',
58 'OPENCOMMENT' => 'file ended with a /* comment still "open"'
61 sub readwhitelist {
62 open(W, "<$dir/checksrc.whitelist");
63 my @all=<W>;
64 for(@all) {
65 $windows_os ? $_ =~ s/\r?\n$// : chomp;
66 $whitelist{$_}=1;
68 close(W);
71 sub checkwarn {
72 my ($name, $num, $col, $file, $line, $msg, $error) = @_;
74 my $w=$error?"error":"warning";
75 my $nowarn=0;
77 #if(!$warnings{$name}) {
78 # print STDERR "Dev! there's no description for $name!\n";
81 # checksrc.whitelist
82 if($whitelist{$line}) {
83 $nowarn = 1;
85 # !checksrc! controlled
86 elsif($ignore{$name}) {
87 $ignore{$name}--;
88 $ignore_used{$name}++;
89 $nowarn = 1;
90 if(!$ignore{$name}) {
91 # reached zero, enable again
92 enable_warn($name, $line, $file, $l);
96 if($nowarn) {
97 $supressed++;
98 if($w) {
99 $swarnings++;
101 else {
102 $serrors++;
104 return;
107 if($w) {
108 $warnings++;
110 else {
111 $errors++;
114 $col++;
115 print "$file:$num:$col: $w: $msg ($name)\n";
116 print " $line\n";
118 if($col < 80) {
119 my $pref = (' ' x $col);
120 print "${pref}^\n";
124 $file = shift @ARGV;
126 while(1) {
128 if($file =~ /-D(.*)/) {
129 $dir = $1;
130 $file = shift @ARGV;
131 next;
133 elsif($file =~ /-W(.*)/) {
134 $wlist .= " $1 ";
135 $file = shift @ARGV;
136 next;
138 elsif($file =~ /^(-h|--help)/) {
139 undef $file;
140 last;
143 last;
146 if(!$file) {
147 print "checksrc.pl [option] <file1> [file2] ...\n";
148 print " Options:\n";
149 print " -D[DIR] Directory to prepend file names\n";
150 print " -h Show help output\n";
151 print " -W[file] Whitelist the given file - ignore all its flaws\n";
152 print "\nDetects and warns for these problems:\n";
153 for(sort keys %warnings) {
154 printf (" %-18s: %s\n", $_, $warnings{$_});
156 exit;
159 readwhitelist();
161 do {
162 if("$wlist" !~ / $file /) {
163 my $fullname = $file;
164 $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/');
165 scanfile($fullname);
167 $file = shift @ARGV;
169 } while($file);
171 sub checksrc_clear {
172 undef %ignore;
173 undef %ignore_set;
174 undef @ignore_line;
177 sub checksrc_endoffile {
178 my ($file) = @_;
179 for(keys %ignore_set) {
180 if($ignore_set{$_} && !$ignore_used{$_}) {
181 checkwarn("UNUSEDIGNORE", $ignore_set{$_},
182 length($_)+11, $file,
183 $ignore_line[$ignore_set{$_}],
184 "Unused ignore: $_");
189 sub enable_warn {
190 my ($what, $line, $file, $l) = @_;
192 # switch it back on, but warn if not triggered!
193 if(!$ignore_used{$what}) {
194 checkwarn("UNUSEDIGNORE",
195 $line, length($what) + 11, $file, $l,
196 "No warning was inhibited!");
198 $ignore_set{$what}=0;
199 $ignore_used{$what}=0;
200 $ignore{$what}=0;
202 sub checksrc {
203 my ($cmd, $line, $file, $l) = @_;
204 if($cmd =~ / *([^ ]*) *(.*)/) {
205 my ($enable, $what) = ($1, $2);
206 $what =~ s: *\*/$::; # cut off end of C comment
207 # print "ENABLE $enable WHAT $what\n";
208 if($enable eq "disable") {
209 my ($warn, $scope)=($1, $2);
210 if($what =~ /([^ ]*) +(.*)/) {
211 ($warn, $scope)=($1, $2);
213 else {
214 $warn = $what;
215 $scope = 1;
217 # print "IGNORE $warn for SCOPE $scope\n";
218 if($scope eq "all") {
219 $scope=999999;
222 if($ignore_set{$warn}) {
223 checkwarn("BADCOMMAND",
224 $line, 0, $file, $l,
225 "$warn already disabled from line $ignore_set{$warn}");
227 else {
228 $ignore{$warn}=$scope;
229 $ignore_set{$warn}=$line;
230 $ignore_line[$line]=$l;
233 elsif($enable eq "enable") {
234 enable_warn($what, $line, $file, $l);
236 else {
237 checkwarn("BADCOMMAND",
238 $line, 0, $file, $l,
239 "Illegal !checksrc! command");
244 sub scanfile {
245 my ($file) = @_;
247 my $line = 1;
248 my $prevl;
249 my $l;
250 open(R, "<$file") || die "failed to open $file";
252 my $incomment=0;
253 my $copyright=0;
254 checksrc_clear(); # for file based ignores
256 while(<R>) {
257 $windows_os ? $_ =~ s/\r?\n$// : chomp;
258 my $l = $_;
259 my $ol = $l; # keep the unmodified line for error reporting
260 my $column = 0;
262 # check for !checksrc! commands
263 if($l =~ /\!checksrc\! (.*)/) {
264 my $cmd = $1;
265 checksrc($cmd, $line, $file, $l)
268 # check for a copyright statement
269 if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) {
270 $copyright=1;
273 # detect long lines
274 if(length($l) > $max_column) {
275 checkwarn("LONGLINE", $line, length($l), $file, $l,
276 "Longer than $max_column columns");
278 # detect TAB characters
279 if($l =~ /^(.*)\t/) {
280 checkwarn("TABS",
281 $line, length($1), $file, $l, "Contains TAB character", 1);
283 # detect trailing white space
284 if($l =~ /^(.*)[ \t]+\z/) {
285 checkwarn("TRAILINGSPACE",
286 $line, length($1), $file, $l, "Trailing whitespace");
289 # ------------------------------------------------------------
290 # Above this marker, the checks were done on lines *including*
291 # comments
292 # ------------------------------------------------------------
294 # strip off C89 comments
296 comment:
297 if(!$incomment) {
298 if($l =~ s/\/\*.*\*\// /g) {
299 # full /* comments */ were removed!
301 if($l =~ s/\/\*.*//) {
302 # start of /* comment was removed
303 $incomment = 1;
306 else {
307 if($l =~ s/.*\*\///) {
308 # end of comment */ was removed
309 $incomment = 0;
310 goto comment;
312 else {
313 # still within a comment
314 $l="";
318 # ------------------------------------------------------------
319 # Below this marker, the checks were done on lines *without*
320 # comments
321 # ------------------------------------------------------------
323 # crude attempt to detect // comments without too many false
324 # positives
325 if($l =~ /^([^"\*]*)[^:"]\/\//) {
326 checkwarn("CPPCOMMENTS",
327 $line, length($1), $file, $l, "\/\/ comment");
330 # check spaces after for/if/while
331 if($l =~ /^(.*)(for|if|while) \(/) {
332 if($1 =~ / *\#/) {
333 # this is a #if, treat it differently
335 else {
336 checkwarn("SPACEBEFOREPAREN", $line, length($1)+length($2), $file, $l,
337 "$2 with space");
341 # check spaces after open parentheses
342 if($l =~ /^(.*[a-z])\( /i) {
343 checkwarn("SPACEAFTERPAREN",
344 $line, length($1)+1, $file, $l,
345 "space after open parenthesis");
348 # check spaces before close parentheses, unless it was a space or a
349 # close parenthesis!
350 if($l =~ /(.*[^\) ]) \)/) {
351 checkwarn("SPACEBEFORECLOSE",
352 $line, length($1)+1, $file, $l,
353 "space before close parenthesis");
356 # check spaces before comma!
357 if($l =~ /(.*[^ ]) ,/) {
358 checkwarn("SPACEBEFORECOMMA",
359 $line, length($1)+1, $file, $l,
360 "space before comma");
363 # check for "return(" without space
364 if($l =~ /^(.*)return\(/) {
365 if($1 =~ / *\#/) {
366 # this is a #if, treat it differently
368 else {
369 checkwarn("RETURNNOSPACE", $line, length($1)+6, $file, $l,
370 "return without space before paren");
374 # check for comma without space
375 if($l =~ /^(.*),[^ \n]/) {
376 my $pref=$1;
377 my $ign=0;
378 if($pref =~ / *\#/) {
379 # this is a #if, treat it differently
380 $ign=1;
382 elsif($pref =~ /\/\*/) {
383 # this is a comment
384 $ign=1;
386 elsif($pref =~ /[\"\']/) {
387 $ign = 1;
388 # There is a quote here, figure out whether the comma is
389 # within a string or '' or not.
390 if($pref =~ /\"/) {
391 # withing a string
393 elsif($pref =~ /\'$/) {
394 # a single letter
396 else {
397 $ign = 0;
400 if(!$ign) {
401 checkwarn("COMMANOSPACE", $line, length($pref)+1, $file, $l,
402 "comma without following space");
406 # check for "} else"
407 if($l =~ /^(.*)\} *else/) {
408 checkwarn("BRACEELSE",
409 $line, length($1), $file, $l, "else after closing brace on same line");
411 # check for "){"
412 if($l =~ /^(.*)\)\{/) {
413 checkwarn("PARENBRACE",
414 $line, length($1)+1, $file, $l, "missing space after close paren");
417 # check for space before the semicolon last in a line
418 if($l =~ /^(.*[^ ].*) ;$/) {
419 checkwarn("SPACESEMILCOLON",
420 $line, length($1), $file, $ol, "space before last semicolon");
423 # scan for use of banned functions
424 if($l =~ /^(.*\W)(sprintf|vsprintf|strcat|strncat|_mbscat|_mbsncat|_tcscat|_tcsncat|wcscat|wcsncat|gets)\s*\(/) {
425 checkwarn("BANNEDFUNC",
426 $line, length($1), $file, $ol,
427 "use of $2 is banned");
430 # scan for use of non-binary fopen without the macro
431 if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) {
432 my $mode = $2;
433 if($mode !~ /b/) {
434 checkwarn("FOPENMODE",
435 $line, length($1), $file, $ol,
436 "use of non-binary fopen without FOPEN_* macro: $mode");
440 # check for open brace first on line but not first column
441 # only alert if previous line ended with a close paren and wasn't a cpp
442 # line
443 if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) {
444 checkwarn("BRACEPOS",
445 $line, length($1), $file, $ol, "badly placed open brace");
448 # if the previous line starts with if/while/for AND ends with an open
449 # brace, check that this line is indented $indent more steps, if not
450 # a cpp line
451 if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) {
452 my $first = length($1);
454 # this line has some character besides spaces
455 if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) {
456 my $second = length($1);
457 my $expect = $first+$indent;
458 if($expect != $second) {
459 my $diff = $second - $first;
460 checkwarn("INDENTATION", $line, length($1), $file, $ol,
461 "not indented $indent steps, uses $diff)");
467 $line++;
468 $prevl = $ol;
471 if(!$copyright) {
472 checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1);
474 if($incomment) {
475 checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1);
478 checksrc_endoffile($file);
480 close(R);
485 if($errors || $warnings || $verbose) {
486 printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
487 if($supressed) {
488 printf "checksrc: %d errors and %d warnings suppressed\n",
489 $serrors,
490 $swarnings;
492 exit 5; # return failure