Imported Upstream version 7.44.0
[platform/upstream/curl.git] / lib / checksrc.pl
1 #!/usr/bin/perl
2 #***************************************************************************
3 #                                  _   _ ____  _
4 #  Project                     ___| | | |  _ \| |
5 #                             / __| | | | |_) | |
6 #                            | (__| |_| |  _ <| |___
7 #                             \___|\___/|_| \_\_____|
8 #
9 # Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
10 #
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 http://curl.haxx.se/docs/copyright.html.
14 #
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.
18 #
19 # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 # KIND, either express or implied.
21 #
22 ###########################################################################
23
24 my $max_column = 79;
25 my $indent = 2;
26
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
35 my %whitelist;
36
37 sub readwhitelist {
38     open(W, "<$dir/checksrc.whitelist");
39     my @all=<W>;
40     for(@all) {
41         $windows_os ? $_ =~ s/\r?\n$// : chomp;
42         $whitelist{$_}=1;
43     }
44     close(W);
45 }
46
47 sub checkwarn {
48     my ($num, $col, $file, $line, $msg, $error) = @_;
49
50     if($whitelist{$line}) {
51         $supressed++;
52         return;
53     }
54     
55     my $w=$error?"error":"warning";
56
57     if($w) {
58         $warnings++;
59     }
60     else {
61         $errors++;
62     }
63
64     $col++;
65     print "$file:$num:$col: $w: $msg\n";
66     print " $line\n";
67
68     if($col < 80) {
69         my $pref = (' ' x $col);
70         print "${pref}^\n";
71     }
72 }
73
74 $file = shift @ARGV;
75
76 while(1) {
77
78     if($file =~ /-D(.*)/) {
79         $dir = $1;
80         $file = shift @ARGV;
81         next;
82     }
83     elsif($file =~ /-W(.*)/) {
84         $wlist .= " $1 ";
85         $file = shift @ARGV;
86         next;
87     }
88
89     last;
90 }
91
92 if(!$file) {
93     print "checksrc.pl [option] <file1> [file2] ...\n";
94     print " Options:\n";
95     print "  -D[DIR]   Directory to prepend file names\n";
96     print "  -W[file]  Whitelist the given file - ignore all its flaws\n";
97     exit;
98 }
99
100 readwhitelist();
101
102 do {
103     if("$wlist" !~ / $file /) {
104         my $fullname = $file;
105         $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/');
106         scanfile($fullname);
107     }
108     $file = shift @ARGV;
109
110 } while($file);
111
112
113 sub scanfile {
114     my ($file) = @_;
115
116     my $line = 1;
117     my $prevl;
118     my $l;
119     open(R, "<$file") || die "failed to open $file";
120
121     my $copyright=0;
122
123     while(<R>) {
124         $windows_os ? $_ =~ s/\r?\n$// : chomp;
125         my $l = $_;
126         my $column = 0;
127
128         # check for a copyright statement
129         if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) {
130             $copyright=1;
131         }
132
133         # detect long lines
134         if(length($l) > $max_column) {
135             checkwarn($line, length($l), $file, $l, "Longer than $max_column columns");
136         }
137         # detect TAB characters
138         if($l =~ /^(.*)\t/) {
139             checkwarn($line, length($1), $file, $l, "Contains TAB character", 1);
140         }
141         # detect trailing white space
142         if($l =~ /^(.*)[ \t]+\z/) {
143             checkwarn($line, length($1), $file, $l, "Trailing whitespace");
144         }
145
146         # check spaces after for/if/while
147         if($l =~ /^(.*)(for|if|while) \(/) {
148             if($1 =~ / *\#/) {
149                 # this is a #if, treat it differently
150             }
151             else {
152                 checkwarn($line, length($1)+length($2), $file, $l,
153                           "$2 with space");
154             }
155         }
156
157         # check spaces after open paren after for/if/while
158         if($l =~ /^(.*)(for|if|while)\( /) {
159             if($1 =~ / *\#/) {
160                 # this is a #if, treat it differently
161             }
162             else {
163                 checkwarn($line, length($1)+length($2)+1, $file, $l,
164                           "$2 with space first in condition");
165             }
166         }
167
168         # check for "return(" without space
169         if($l =~ /^(.*)return\(/) {
170             if($1 =~ / *\#/) {
171                 # this is a #if, treat it differently
172             }
173             else {
174                 checkwarn($line, length($1)+6, $file, $l,
175                           "return without space before paren");
176             }
177         }
178
179         # check for comma without space
180         if($l =~ /^(.*),[^ \n]/) {
181             my $pref=$1;
182             my $ign=0;
183             if($pref =~ / *\#/) {
184                 # this is a #if, treat it differently
185                 $ign=1;
186             }
187             elsif($pref =~ /\/\*/) {
188                 # this is a comment
189                 $ign=1;
190             }
191             elsif($pref =~ /[\"\']/) {
192                 $ign = 1;
193                 # There is a quote here, figure out whether the comma is
194                 # within a string or '' or not.
195                 if($pref =~ /\"/) {
196                     # withing a string
197                 }
198                 elsif($pref =~ /\'$/) {
199                     # a single letter
200                 }
201                 else {
202                     $ign = 0;
203                 }
204             }
205             if(!$ign) {
206                 checkwarn($line, length($pref)+1, $file, $l,
207                           "comma without following space");
208             }
209         }
210         
211         # check for "} else"
212         if($l =~ /^(.*)\} *else/) {
213             checkwarn($line, length($1), $file, $l, "else after closing brace on same line");
214         }
215         # check for "){"
216         if($l =~ /^(.*)\)\{/) {
217             checkwarn($line, length($1)+1, $file, $l, "missing space after close paren");
218         }
219
220         # check for space before the semicolon last in a line
221         if($l =~ /^(.*[^ ].*) ;$/) {
222             checkwarn($line, length($1), $file, $l, "space before last semicolon");
223         }
224
225         # scan for use of banned functions
226         if($l =~ /^(.*\W)(sprintf|vsprintf|strcat|strncat|gets)\s*\(/) {
227             checkwarn($line, length($1), $file, $l,
228                       "use of $2 is banned");
229         }
230
231         # scan for use of non-binary fopen without the macro
232         if($l =~ /^(.*\W)fopen\s*\([^"]*\"([^"]*)/) {
233             my $mode = $2;
234             if($mode !~ /b/) {
235                 checkwarn($line, length($1), $file, $l,
236                           "use of non-binary fopen without FOPEN_* macro");
237             }
238         }
239
240         # check for open brace first on line but not first column
241         # only alert if previous line ended with a close paren and wasn't a cpp
242         # line
243         if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) {
244             checkwarn($line, length($1), $file, $l, "badly placed open brace");
245         }
246
247         # if the previous line starts with if/while/for AND ends with an open
248         # brace, check that this line is indented $indent more steps, if not
249         # a cpp line
250         if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) {
251             my $first = length($1);
252
253             # this line has some character besides spaces
254             if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) {
255                 my $second = length($1);
256                 my $expect = $first+$indent;
257                 if($expect != $second) {
258                     my $diff = $second - $first;
259                     checkwarn($line, length($1), $file, $l,
260                               "not indented $indent steps, uses $diff)");
261
262                 }
263             }
264         }
265
266         $line++;
267         $prevl = $l;
268     }
269
270     if(!$copyright) {
271         checkwarn(1, 0, $file, "", "Missing copyright statement", 1);
272     }
273
274     close(R);
275
276 }
277
278
279 if($errors || $warnings) {
280     printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
281     exit 5; # return failure
282 }