Imported Upstream version 7.48.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 https://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         # crude attempt to detect // comments without too many false
147         # positives
148         if($l =~ /^([^"\*]*)[^:"]\/\//) {
149             checkwarn($line, length($1), $file, $l, "\/\/ comment");
150         }
151         # check spaces after for/if/while
152         if($l =~ /^(.*)(for|if|while) \(/) {
153             if($1 =~ / *\#/) {
154                 # this is a #if, treat it differently
155             }
156             else {
157                 checkwarn($line, length($1)+length($2), $file, $l,
158                           "$2 with space");
159             }
160         }
161
162         # check spaces after open paren after for/if/while
163         if($l =~ /^(.*)(for|if|while)\( /) {
164             if($1 =~ / *\#/) {
165                 # this is a #if, treat it differently
166             }
167             else {
168                 checkwarn($line, length($1)+length($2)+1, $file, $l,
169                           "$2 with space first in condition");
170             }
171         }
172
173         # check for "return(" without space
174         if($l =~ /^(.*)return\(/) {
175             if($1 =~ / *\#/) {
176                 # this is a #if, treat it differently
177             }
178             else {
179                 checkwarn($line, length($1)+6, $file, $l,
180                           "return without space before paren");
181             }
182         }
183
184         # check for comma without space
185         if($l =~ /^(.*),[^ \n]/) {
186             my $pref=$1;
187             my $ign=0;
188             if($pref =~ / *\#/) {
189                 # this is a #if, treat it differently
190                 $ign=1;
191             }
192             elsif($pref =~ /\/\*/) {
193                 # this is a comment
194                 $ign=1;
195             }
196             elsif($pref =~ /[\"\']/) {
197                 $ign = 1;
198                 # There is a quote here, figure out whether the comma is
199                 # within a string or '' or not.
200                 if($pref =~ /\"/) {
201                     # withing a string
202                 }
203                 elsif($pref =~ /\'$/) {
204                     # a single letter
205                 }
206                 else {
207                     $ign = 0;
208                 }
209             }
210             if(!$ign) {
211                 checkwarn($line, length($pref)+1, $file, $l,
212                           "comma without following space");
213             }
214         }
215         
216         # check for "} else"
217         if($l =~ /^(.*)\} *else/) {
218             checkwarn($line, length($1), $file, $l, "else after closing brace on same line");
219         }
220         # check for "){"
221         if($l =~ /^(.*)\)\{/) {
222             checkwarn($line, length($1)+1, $file, $l, "missing space after close paren");
223         }
224
225         # check for space before the semicolon last in a line
226         if($l =~ /^(.*[^ ].*) ;$/) {
227             checkwarn($line, length($1), $file, $l, "space before last semicolon");
228         }
229
230         # scan for use of banned functions
231         if($l =~ /^(.*\W)(sprintf|vsprintf|strcat|strncat|gets)\s*\(/) {
232             checkwarn($line, length($1), $file, $l,
233                       "use of $2 is banned");
234         }
235
236         # scan for use of non-binary fopen without the macro
237         if($l =~ /^(.*\W)fopen\s*\([^"]*\"([^"]*)/) {
238             my $mode = $2;
239             if($mode !~ /b/) {
240                 checkwarn($line, length($1), $file, $l,
241                           "use of non-binary fopen without FOPEN_* macro");
242             }
243         }
244
245         # check for open brace first on line but not first column
246         # only alert if previous line ended with a close paren and wasn't a cpp
247         # line
248         if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) {
249             checkwarn($line, length($1), $file, $l, "badly placed open brace");
250         }
251
252         # if the previous line starts with if/while/for AND ends with an open
253         # brace, check that this line is indented $indent more steps, if not
254         # a cpp line
255         if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) {
256             my $first = length($1);
257
258             # this line has some character besides spaces
259             if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) {
260                 my $second = length($1);
261                 my $expect = $first+$indent;
262                 if($expect != $second) {
263                     my $diff = $second - $first;
264                     checkwarn($line, length($1), $file, $l,
265                               "not indented $indent steps, uses $diff)");
266
267                 }
268             }
269         }
270
271         $line++;
272         $prevl = $l;
273     }
274
275     if(!$copyright) {
276         checkwarn(1, 0, $file, "", "Missing copyright statement", 1);
277     }
278
279     close(R);
280
281 }
282
283
284 if($errors || $warnings) {
285     printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
286     exit 5; # return failure
287 }