xref: /aosp_15_r20/external/curl/scripts/checksrc.pl (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker#!/usr/bin/env perl
2*6236dae4SAndroid Build Coastguard Worker#***************************************************************************
3*6236dae4SAndroid Build Coastguard Worker#                                  _   _ ____  _
4*6236dae4SAndroid Build Coastguard Worker#  Project                     ___| | | |  _ \| |
5*6236dae4SAndroid Build Coastguard Worker#                             / __| | | | |_) | |
6*6236dae4SAndroid Build Coastguard Worker#                            | (__| |_| |  _ <| |___
7*6236dae4SAndroid Build Coastguard Worker#                             \___|\___/|_| \_\_____|
8*6236dae4SAndroid Build Coastguard Worker#
9*6236dae4SAndroid Build Coastguard Worker# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
10*6236dae4SAndroid Build Coastguard Worker#
11*6236dae4SAndroid Build Coastguard Worker# This software is licensed as described in the file COPYING, which
12*6236dae4SAndroid Build Coastguard Worker# you should have received as part of this distribution. The terms
13*6236dae4SAndroid Build Coastguard Worker# are also available at https://curl.se/docs/copyright.html.
14*6236dae4SAndroid Build Coastguard Worker#
15*6236dae4SAndroid Build Coastguard Worker# You may opt to use, copy, modify, merge, publish, distribute and/or sell
16*6236dae4SAndroid Build Coastguard Worker# copies of the Software, and permit persons to whom the Software is
17*6236dae4SAndroid Build Coastguard Worker# furnished to do so, under the terms of the COPYING file.
18*6236dae4SAndroid Build Coastguard Worker#
19*6236dae4SAndroid Build Coastguard Worker# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20*6236dae4SAndroid Build Coastguard Worker# KIND, either express or implied.
21*6236dae4SAndroid Build Coastguard Worker#
22*6236dae4SAndroid Build Coastguard Worker# SPDX-License-Identifier: curl
23*6236dae4SAndroid Build Coastguard Worker#
24*6236dae4SAndroid Build Coastguard Worker###########################################################################
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Workeruse strict;
27*6236dae4SAndroid Build Coastguard Workeruse warnings;
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Workermy $max_column = 79;
30*6236dae4SAndroid Build Coastguard Workermy $indent = 2;
31*6236dae4SAndroid Build Coastguard Worker
32*6236dae4SAndroid Build Coastguard Workermy $warnings = 0;
33*6236dae4SAndroid Build Coastguard Workermy $swarnings = 0;
34*6236dae4SAndroid Build Coastguard Workermy $errors = 0;
35*6236dae4SAndroid Build Coastguard Workermy $serrors = 0;
36*6236dae4SAndroid Build Coastguard Workermy $suppressed; # skipped problems
37*6236dae4SAndroid Build Coastguard Workermy $file;
38*6236dae4SAndroid Build Coastguard Workermy $dir=".";
39*6236dae4SAndroid Build Coastguard Workermy $wlist="";
40*6236dae4SAndroid Build Coastguard Workermy @alist;
41*6236dae4SAndroid Build Coastguard Workermy $windows_os = $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys';
42*6236dae4SAndroid Build Coastguard Workermy $verbose;
43*6236dae4SAndroid Build Coastguard Workermy %skiplist;
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Workermy %ignore;
46*6236dae4SAndroid Build Coastguard Workermy %ignore_set;
47*6236dae4SAndroid Build Coastguard Workermy %ignore_used;
48*6236dae4SAndroid Build Coastguard Workermy @ignore_line;
49*6236dae4SAndroid Build Coastguard Worker
50*6236dae4SAndroid Build Coastguard Workermy %warnings_extended = (
51*6236dae4SAndroid Build Coastguard Worker    'COPYRIGHTYEAR'    => 'copyright year incorrect',
52*6236dae4SAndroid Build Coastguard Worker    'STRERROR',        => 'strerror() detected',
53*6236dae4SAndroid Build Coastguard Worker    'STRNCPY',         => 'strncpy() detected',
54*6236dae4SAndroid Build Coastguard Worker    'STDERR',          => 'stderr detected',
55*6236dae4SAndroid Build Coastguard Worker    );
56*6236dae4SAndroid Build Coastguard Worker
57*6236dae4SAndroid Build Coastguard Workermy %warnings = (
58*6236dae4SAndroid Build Coastguard Worker    'ASSIGNWITHINCONDITION' => 'assignment within conditional expression',
59*6236dae4SAndroid Build Coastguard Worker    'ASTERISKNOSPACE'       => 'pointer declared without space before asterisk',
60*6236dae4SAndroid Build Coastguard Worker    'ASTERISKSPACE'         => 'pointer declared with space after asterisk',
61*6236dae4SAndroid Build Coastguard Worker    'BADCOMMAND'            => 'bad !checksrc! instruction',
62*6236dae4SAndroid Build Coastguard Worker    'BANNEDFUNC'            => 'a banned function was used',
63*6236dae4SAndroid Build Coastguard Worker    'BANNEDPREPROC'         => 'a banned symbol was used on a preprocessor line',
64*6236dae4SAndroid Build Coastguard Worker    'BRACEELSE'             => '} else on the same line',
65*6236dae4SAndroid Build Coastguard Worker    'BRACEPOS'              => 'wrong position for an open brace',
66*6236dae4SAndroid Build Coastguard Worker    'BRACEWHILE'            => 'A single space between open brace and while',
67*6236dae4SAndroid Build Coastguard Worker    'COMMANOSPACE'          => 'comma without following space',
68*6236dae4SAndroid Build Coastguard Worker    'COMMENTNOSPACEEND'     => 'no space before */',
69*6236dae4SAndroid Build Coastguard Worker    'COMMENTNOSPACESTART'   => 'no space following /*',
70*6236dae4SAndroid Build Coastguard Worker    'COPYRIGHT'             => 'file missing a copyright statement',
71*6236dae4SAndroid Build Coastguard Worker    'CPPCOMMENTS'           => '// comment detected',
72*6236dae4SAndroid Build Coastguard Worker    'DOBRACE'               => 'A single space between do and open brace',
73*6236dae4SAndroid Build Coastguard Worker    'EMPTYLINEBRACE'        => 'Empty line before the open brace',
74*6236dae4SAndroid Build Coastguard Worker    'EQUALSNOSPACE'         => 'equals sign without following space',
75*6236dae4SAndroid Build Coastguard Worker    'EQUALSNULL'            => 'if/while comparison with == NULL',
76*6236dae4SAndroid Build Coastguard Worker    'EXCLAMATIONSPACE'      => 'Whitespace after exclamation mark in expression',
77*6236dae4SAndroid Build Coastguard Worker    'FOPENMODE'             => 'fopen needs a macro for the mode string',
78*6236dae4SAndroid Build Coastguard Worker    'INCLUDEDUP',           => 'same file is included again',
79*6236dae4SAndroid Build Coastguard Worker    'INDENTATION'           => 'wrong start column for code',
80*6236dae4SAndroid Build Coastguard Worker    'LONGLINE'              => "Line longer than $max_column",
81*6236dae4SAndroid Build Coastguard Worker    'SPACEBEFORELABEL'      => 'labels not at the start of the line',
82*6236dae4SAndroid Build Coastguard Worker    'MULTISPACE'            => 'multiple spaces used when not suitable',
83*6236dae4SAndroid Build Coastguard Worker    'NOSPACEAND'            => 'missing space around Logical AND operator',
84*6236dae4SAndroid Build Coastguard Worker    'NOSPACEC'              => 'missing space around ternary colon operator',
85*6236dae4SAndroid Build Coastguard Worker    'NOSPACEEQUALS'         => 'equals sign without preceding space',
86*6236dae4SAndroid Build Coastguard Worker    'NOSPACEQ'              => 'missing space around ternary question mark operator',
87*6236dae4SAndroid Build Coastguard Worker    'NOSPACETHAN'           => 'missing space around less or greater than',
88*6236dae4SAndroid Build Coastguard Worker    'NOTEQUALSZERO',        => 'if/while comparison with != 0',
89*6236dae4SAndroid Build Coastguard Worker    'ONELINECONDITION'      => 'conditional block on the same line as the if()',
90*6236dae4SAndroid Build Coastguard Worker    'OPENCOMMENT'           => 'file ended with a /* comment still "open"',
91*6236dae4SAndroid Build Coastguard Worker    'PARENBRACE'            => '){ without sufficient space',
92*6236dae4SAndroid Build Coastguard Worker    'RETURNNOSPACE'         => 'return without space',
93*6236dae4SAndroid Build Coastguard Worker    'SEMINOSPACE'           => 'semicolon without following space',
94*6236dae4SAndroid Build Coastguard Worker    'SIZEOFNOPAREN'         => 'use of sizeof without parentheses',
95*6236dae4SAndroid Build Coastguard Worker    'SNPRINTF'              => 'use of snprintf',
96*6236dae4SAndroid Build Coastguard Worker    'SPACEAFTERPAREN'       => 'space after open parenthesis',
97*6236dae4SAndroid Build Coastguard Worker    'SPACEBEFORECLOSE'      => 'space before a close parenthesis',
98*6236dae4SAndroid Build Coastguard Worker    'SPACEBEFORECOMMA'      => 'space before a comma',
99*6236dae4SAndroid Build Coastguard Worker    'SPACEBEFOREPAREN'      => 'space before an open parenthesis',
100*6236dae4SAndroid Build Coastguard Worker    'SPACESEMICOLON'        => 'space before semicolon',
101*6236dae4SAndroid Build Coastguard Worker    'SPACESWITCHCOLON'      => 'space before colon of switch label',
102*6236dae4SAndroid Build Coastguard Worker    'TABS'                  => 'TAB characters not allowed',
103*6236dae4SAndroid Build Coastguard Worker    'TRAILINGSPACE'         => 'Trailing whitespace on the line',
104*6236dae4SAndroid Build Coastguard Worker    'TYPEDEFSTRUCT'         => 'typedefed struct',
105*6236dae4SAndroid Build Coastguard Worker    'UNUSEDIGNORE'          => 'a warning ignore was not used',
106*6236dae4SAndroid Build Coastguard Worker    );
107*6236dae4SAndroid Build Coastguard Worker
108*6236dae4SAndroid Build Coastguard Workersub readskiplist {
109*6236dae4SAndroid Build Coastguard Worker    open(my $W, '<', "$dir/checksrc.skip") or return;
110*6236dae4SAndroid Build Coastguard Worker    my @all=<$W>;
111*6236dae4SAndroid Build Coastguard Worker    for(@all) {
112*6236dae4SAndroid Build Coastguard Worker        $windows_os ? $_ =~ s/\r?\n$// : chomp;
113*6236dae4SAndroid Build Coastguard Worker        $skiplist{$_}=1;
114*6236dae4SAndroid Build Coastguard Worker    }
115*6236dae4SAndroid Build Coastguard Worker    close($W);
116*6236dae4SAndroid Build Coastguard Worker}
117*6236dae4SAndroid Build Coastguard Worker
118*6236dae4SAndroid Build Coastguard Worker# Reads the .checksrc in $dir for any extended warnings to enable locally.
119*6236dae4SAndroid Build Coastguard Worker# Currently there is no support for disabling warnings from the standard set,
120*6236dae4SAndroid Build Coastguard Worker# and since that's already handled via !checksrc! commands there is probably
121*6236dae4SAndroid Build Coastguard Worker# little use to add it.
122*6236dae4SAndroid Build Coastguard Workersub readlocalfile {
123*6236dae4SAndroid Build Coastguard Worker    my ($file) = @_;
124*6236dae4SAndroid Build Coastguard Worker    my $i = 0;
125*6236dae4SAndroid Build Coastguard Worker    my $rcfile;
126*6236dae4SAndroid Build Coastguard Worker
127*6236dae4SAndroid Build Coastguard Worker    if(($dir eq ".") && $file =~ /\//) {
128*6236dae4SAndroid Build Coastguard Worker        my $ldir;
129*6236dae4SAndroid Build Coastguard Worker        if($file =~ /(.*)\//) {
130*6236dae4SAndroid Build Coastguard Worker            $ldir = $1;
131*6236dae4SAndroid Build Coastguard Worker            open($rcfile, "<", "$dir/$ldir/.checksrc") or return;
132*6236dae4SAndroid Build Coastguard Worker        }
133*6236dae4SAndroid Build Coastguard Worker    }
134*6236dae4SAndroid Build Coastguard Worker    else {
135*6236dae4SAndroid Build Coastguard Worker        open($rcfile, "<", "$dir/.checksrc") or return;
136*6236dae4SAndroid Build Coastguard Worker    }
137*6236dae4SAndroid Build Coastguard Worker
138*6236dae4SAndroid Build Coastguard Worker    while(<$rcfile>) {
139*6236dae4SAndroid Build Coastguard Worker        $windows_os ? $_ =~ s/\r?\n$// : chomp;
140*6236dae4SAndroid Build Coastguard Worker        $i++;
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker        # Lines starting with '#' are considered comments
143*6236dae4SAndroid Build Coastguard Worker        if (/^\s*(#.*)/) {
144*6236dae4SAndroid Build Coastguard Worker            next;
145*6236dae4SAndroid Build Coastguard Worker        }
146*6236dae4SAndroid Build Coastguard Worker        elsif (/^\s*enable ([A-Z]+)$/) {
147*6236dae4SAndroid Build Coastguard Worker            if(!defined($warnings_extended{$1})) {
148*6236dae4SAndroid Build Coastguard Worker                print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
149*6236dae4SAndroid Build Coastguard Worker                next;
150*6236dae4SAndroid Build Coastguard Worker            }
151*6236dae4SAndroid Build Coastguard Worker            $warnings{$1} = $warnings_extended{$1};
152*6236dae4SAndroid Build Coastguard Worker        }
153*6236dae4SAndroid Build Coastguard Worker        elsif (/^\s*disable ([A-Z]+)$/) {
154*6236dae4SAndroid Build Coastguard Worker            if(!defined($warnings{$1})) {
155*6236dae4SAndroid Build Coastguard Worker                print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
156*6236dae4SAndroid Build Coastguard Worker                next;
157*6236dae4SAndroid Build Coastguard Worker            }
158*6236dae4SAndroid Build Coastguard Worker            # Accept-list
159*6236dae4SAndroid Build Coastguard Worker            push @alist, $1;
160*6236dae4SAndroid Build Coastguard Worker        }
161*6236dae4SAndroid Build Coastguard Worker        else {
162*6236dae4SAndroid Build Coastguard Worker            die "Invalid format in $dir/.checksrc on line $i\n";
163*6236dae4SAndroid Build Coastguard Worker        }
164*6236dae4SAndroid Build Coastguard Worker    }
165*6236dae4SAndroid Build Coastguard Worker    close($rcfile);
166*6236dae4SAndroid Build Coastguard Worker}
167*6236dae4SAndroid Build Coastguard Worker
168*6236dae4SAndroid Build Coastguard Workersub checkwarn {
169*6236dae4SAndroid Build Coastguard Worker    my ($name, $num, $col, $file, $line, $msg, $error) = @_;
170*6236dae4SAndroid Build Coastguard Worker
171*6236dae4SAndroid Build Coastguard Worker    my $w=$error?"error":"warning";
172*6236dae4SAndroid Build Coastguard Worker    my $nowarn=0;
173*6236dae4SAndroid Build Coastguard Worker
174*6236dae4SAndroid Build Coastguard Worker    #if(!$warnings{$name}) {
175*6236dae4SAndroid Build Coastguard Worker    #    print STDERR "Dev! there's no description for $name!\n";
176*6236dae4SAndroid Build Coastguard Worker    #}
177*6236dae4SAndroid Build Coastguard Worker
178*6236dae4SAndroid Build Coastguard Worker    # checksrc.skip
179*6236dae4SAndroid Build Coastguard Worker    if($skiplist{$line}) {
180*6236dae4SAndroid Build Coastguard Worker        $nowarn = 1;
181*6236dae4SAndroid Build Coastguard Worker    }
182*6236dae4SAndroid Build Coastguard Worker    # !checksrc! controlled
183*6236dae4SAndroid Build Coastguard Worker    elsif($ignore{$name}) {
184*6236dae4SAndroid Build Coastguard Worker        $ignore{$name}--;
185*6236dae4SAndroid Build Coastguard Worker        $ignore_used{$name}++;
186*6236dae4SAndroid Build Coastguard Worker        $nowarn = 1;
187*6236dae4SAndroid Build Coastguard Worker        if(!$ignore{$name}) {
188*6236dae4SAndroid Build Coastguard Worker            # reached zero, enable again
189*6236dae4SAndroid Build Coastguard Worker            enable_warn($name, $num, $file, $line);
190*6236dae4SAndroid Build Coastguard Worker        }
191*6236dae4SAndroid Build Coastguard Worker    }
192*6236dae4SAndroid Build Coastguard Worker
193*6236dae4SAndroid Build Coastguard Worker    if($nowarn) {
194*6236dae4SAndroid Build Coastguard Worker        $suppressed++;
195*6236dae4SAndroid Build Coastguard Worker        if($w) {
196*6236dae4SAndroid Build Coastguard Worker            $swarnings++;
197*6236dae4SAndroid Build Coastguard Worker        }
198*6236dae4SAndroid Build Coastguard Worker        else {
199*6236dae4SAndroid Build Coastguard Worker            $serrors++;
200*6236dae4SAndroid Build Coastguard Worker        }
201*6236dae4SAndroid Build Coastguard Worker        return;
202*6236dae4SAndroid Build Coastguard Worker    }
203*6236dae4SAndroid Build Coastguard Worker
204*6236dae4SAndroid Build Coastguard Worker    if($w) {
205*6236dae4SAndroid Build Coastguard Worker        $warnings++;
206*6236dae4SAndroid Build Coastguard Worker    }
207*6236dae4SAndroid Build Coastguard Worker    else {
208*6236dae4SAndroid Build Coastguard Worker        $errors++;
209*6236dae4SAndroid Build Coastguard Worker    }
210*6236dae4SAndroid Build Coastguard Worker
211*6236dae4SAndroid Build Coastguard Worker    $col++;
212*6236dae4SAndroid Build Coastguard Worker    print "$file:$num:$col: $w: $msg ($name)\n";
213*6236dae4SAndroid Build Coastguard Worker    print " $line\n";
214*6236dae4SAndroid Build Coastguard Worker
215*6236dae4SAndroid Build Coastguard Worker    if($col < 80) {
216*6236dae4SAndroid Build Coastguard Worker        my $pref = (' ' x $col);
217*6236dae4SAndroid Build Coastguard Worker        print "${pref}^\n";
218*6236dae4SAndroid Build Coastguard Worker    }
219*6236dae4SAndroid Build Coastguard Worker}
220*6236dae4SAndroid Build Coastguard Worker
221*6236dae4SAndroid Build Coastguard Worker$file = shift @ARGV;
222*6236dae4SAndroid Build Coastguard Worker
223*6236dae4SAndroid Build Coastguard Workerwhile(defined $file) {
224*6236dae4SAndroid Build Coastguard Worker
225*6236dae4SAndroid Build Coastguard Worker    if($file =~ /-D(.*)/) {
226*6236dae4SAndroid Build Coastguard Worker        $dir = $1;
227*6236dae4SAndroid Build Coastguard Worker        $file = shift @ARGV;
228*6236dae4SAndroid Build Coastguard Worker        next;
229*6236dae4SAndroid Build Coastguard Worker    }
230*6236dae4SAndroid Build Coastguard Worker    elsif($file =~ /-W(.*)/) {
231*6236dae4SAndroid Build Coastguard Worker        $wlist .= " $1 ";
232*6236dae4SAndroid Build Coastguard Worker        $file = shift @ARGV;
233*6236dae4SAndroid Build Coastguard Worker        next;
234*6236dae4SAndroid Build Coastguard Worker    }
235*6236dae4SAndroid Build Coastguard Worker    elsif($file =~ /-A(.+)/) {
236*6236dae4SAndroid Build Coastguard Worker        push @alist, $1;
237*6236dae4SAndroid Build Coastguard Worker        $file = shift @ARGV;
238*6236dae4SAndroid Build Coastguard Worker        next;
239*6236dae4SAndroid Build Coastguard Worker    }
240*6236dae4SAndroid Build Coastguard Worker    elsif($file =~ /-i([1-9])/) {
241*6236dae4SAndroid Build Coastguard Worker        $indent = $1 + 0;
242*6236dae4SAndroid Build Coastguard Worker        $file = shift @ARGV;
243*6236dae4SAndroid Build Coastguard Worker        next;
244*6236dae4SAndroid Build Coastguard Worker    }
245*6236dae4SAndroid Build Coastguard Worker    elsif($file =~ /-m([0-9]+)/) {
246*6236dae4SAndroid Build Coastguard Worker        $max_column = $1 + 0;
247*6236dae4SAndroid Build Coastguard Worker        $file = shift @ARGV;
248*6236dae4SAndroid Build Coastguard Worker        next;
249*6236dae4SAndroid Build Coastguard Worker    }
250*6236dae4SAndroid Build Coastguard Worker    elsif($file =~ /^(-h|--help)/) {
251*6236dae4SAndroid Build Coastguard Worker        undef $file;
252*6236dae4SAndroid Build Coastguard Worker        last;
253*6236dae4SAndroid Build Coastguard Worker    }
254*6236dae4SAndroid Build Coastguard Worker
255*6236dae4SAndroid Build Coastguard Worker    last;
256*6236dae4SAndroid Build Coastguard Worker}
257*6236dae4SAndroid Build Coastguard Worker
258*6236dae4SAndroid Build Coastguard Workerif(!$file) {
259*6236dae4SAndroid Build Coastguard Worker    print "checksrc.pl [option] <file1> [file2] ...\n";
260*6236dae4SAndroid Build Coastguard Worker    print " Options:\n";
261*6236dae4SAndroid Build Coastguard Worker    print "  -A[rule]  Accept this violation, can be used multiple times\n";
262*6236dae4SAndroid Build Coastguard Worker    print "  -D[DIR]   Directory to prepend file names\n";
263*6236dae4SAndroid Build Coastguard Worker    print "  -h        Show help output\n";
264*6236dae4SAndroid Build Coastguard Worker    print "  -W[file]  Skip the given file - ignore all its flaws\n";
265*6236dae4SAndroid Build Coastguard Worker    print "  -i<n>     Indent spaces. Default: 2\n";
266*6236dae4SAndroid Build Coastguard Worker    print "  -m<n>     Maximum line length. Default: 79\n";
267*6236dae4SAndroid Build Coastguard Worker    print "\nDetects and warns for these problems:\n";
268*6236dae4SAndroid Build Coastguard Worker    my @allw = keys %warnings;
269*6236dae4SAndroid Build Coastguard Worker    push @allw, keys %warnings_extended;
270*6236dae4SAndroid Build Coastguard Worker    for my $w (sort @allw) {
271*6236dae4SAndroid Build Coastguard Worker        if($warnings{$w}) {
272*6236dae4SAndroid Build Coastguard Worker            printf (" %-18s: %s\n", $w, $warnings{$w});
273*6236dae4SAndroid Build Coastguard Worker        }
274*6236dae4SAndroid Build Coastguard Worker        else {
275*6236dae4SAndroid Build Coastguard Worker            printf (" %-18s: %s[*]\n", $w, $warnings_extended{$w});
276*6236dae4SAndroid Build Coastguard Worker        }
277*6236dae4SAndroid Build Coastguard Worker    }
278*6236dae4SAndroid Build Coastguard Worker    print " [*] = disabled by default\n";
279*6236dae4SAndroid Build Coastguard Worker    exit;
280*6236dae4SAndroid Build Coastguard Worker}
281*6236dae4SAndroid Build Coastguard Worker
282*6236dae4SAndroid Build Coastguard Workerreadskiplist();
283*6236dae4SAndroid Build Coastguard Workerreadlocalfile($file);
284*6236dae4SAndroid Build Coastguard Worker
285*6236dae4SAndroid Build Coastguard Workerdo {
286*6236dae4SAndroid Build Coastguard Worker    if("$wlist" !~ / $file /) {
287*6236dae4SAndroid Build Coastguard Worker        my $fullname = $file;
288*6236dae4SAndroid Build Coastguard Worker        $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/');
289*6236dae4SAndroid Build Coastguard Worker        scanfile($fullname);
290*6236dae4SAndroid Build Coastguard Worker    }
291*6236dae4SAndroid Build Coastguard Worker    $file = shift @ARGV;
292*6236dae4SAndroid Build Coastguard Worker
293*6236dae4SAndroid Build Coastguard Worker} while($file);
294*6236dae4SAndroid Build Coastguard Worker
295*6236dae4SAndroid Build Coastguard Workersub accept_violations {
296*6236dae4SAndroid Build Coastguard Worker    for my $r (@alist) {
297*6236dae4SAndroid Build Coastguard Worker        if(!$warnings{$r}) {
298*6236dae4SAndroid Build Coastguard Worker            print "'$r' is not a warning to accept!\n";
299*6236dae4SAndroid Build Coastguard Worker            exit;
300*6236dae4SAndroid Build Coastguard Worker        }
301*6236dae4SAndroid Build Coastguard Worker        $ignore{$r}=999999;
302*6236dae4SAndroid Build Coastguard Worker        $ignore_used{$r}=0;
303*6236dae4SAndroid Build Coastguard Worker    }
304*6236dae4SAndroid Build Coastguard Worker}
305*6236dae4SAndroid Build Coastguard Worker
306*6236dae4SAndroid Build Coastguard Workersub checksrc_clear {
307*6236dae4SAndroid Build Coastguard Worker    undef %ignore;
308*6236dae4SAndroid Build Coastguard Worker    undef %ignore_set;
309*6236dae4SAndroid Build Coastguard Worker    undef @ignore_line;
310*6236dae4SAndroid Build Coastguard Worker}
311*6236dae4SAndroid Build Coastguard Worker
312*6236dae4SAndroid Build Coastguard Workersub checksrc_endoffile {
313*6236dae4SAndroid Build Coastguard Worker    my ($file) = @_;
314*6236dae4SAndroid Build Coastguard Worker    for(keys %ignore_set) {
315*6236dae4SAndroid Build Coastguard Worker        if($ignore_set{$_} && !$ignore_used{$_}) {
316*6236dae4SAndroid Build Coastguard Worker            checkwarn("UNUSEDIGNORE", $ignore_set{$_},
317*6236dae4SAndroid Build Coastguard Worker                      length($_)+11, $file,
318*6236dae4SAndroid Build Coastguard Worker                      $ignore_line[$ignore_set{$_}],
319*6236dae4SAndroid Build Coastguard Worker                      "Unused ignore: $_");
320*6236dae4SAndroid Build Coastguard Worker        }
321*6236dae4SAndroid Build Coastguard Worker    }
322*6236dae4SAndroid Build Coastguard Worker}
323*6236dae4SAndroid Build Coastguard Worker
324*6236dae4SAndroid Build Coastguard Workersub enable_warn {
325*6236dae4SAndroid Build Coastguard Worker    my ($what, $line, $file, $l) = @_;
326*6236dae4SAndroid Build Coastguard Worker
327*6236dae4SAndroid Build Coastguard Worker    # switch it back on, but warn if not triggered!
328*6236dae4SAndroid Build Coastguard Worker    if(!$ignore_used{$what}) {
329*6236dae4SAndroid Build Coastguard Worker        checkwarn("UNUSEDIGNORE",
330*6236dae4SAndroid Build Coastguard Worker                  $line, length($what) + 11, $file, $l,
331*6236dae4SAndroid Build Coastguard Worker                  "No warning was inhibited!");
332*6236dae4SAndroid Build Coastguard Worker    }
333*6236dae4SAndroid Build Coastguard Worker    $ignore_set{$what}=0;
334*6236dae4SAndroid Build Coastguard Worker    $ignore_used{$what}=0;
335*6236dae4SAndroid Build Coastguard Worker    $ignore{$what}=0;
336*6236dae4SAndroid Build Coastguard Worker}
337*6236dae4SAndroid Build Coastguard Workersub checksrc {
338*6236dae4SAndroid Build Coastguard Worker    my ($cmd, $line, $file, $l) = @_;
339*6236dae4SAndroid Build Coastguard Worker    if($cmd =~ / *([^ ]*) *(.*)/) {
340*6236dae4SAndroid Build Coastguard Worker        my ($enable, $what) = ($1, $2);
341*6236dae4SAndroid Build Coastguard Worker        $what =~ s: *\*/$::; # cut off end of C comment
342*6236dae4SAndroid Build Coastguard Worker        # print "ENABLE $enable WHAT $what\n";
343*6236dae4SAndroid Build Coastguard Worker        if($enable eq "disable") {
344*6236dae4SAndroid Build Coastguard Worker            my ($warn, $scope)=($1, $2);
345*6236dae4SAndroid Build Coastguard Worker            if($what =~ /([^ ]*) +(.*)/) {
346*6236dae4SAndroid Build Coastguard Worker                ($warn, $scope)=($1, $2);
347*6236dae4SAndroid Build Coastguard Worker            }
348*6236dae4SAndroid Build Coastguard Worker            else {
349*6236dae4SAndroid Build Coastguard Worker                $warn = $what;
350*6236dae4SAndroid Build Coastguard Worker                $scope = 1;
351*6236dae4SAndroid Build Coastguard Worker            }
352*6236dae4SAndroid Build Coastguard Worker            # print "IGNORE $warn for SCOPE $scope\n";
353*6236dae4SAndroid Build Coastguard Worker            if($scope eq "all") {
354*6236dae4SAndroid Build Coastguard Worker                $scope=999999;
355*6236dae4SAndroid Build Coastguard Worker            }
356*6236dae4SAndroid Build Coastguard Worker
357*6236dae4SAndroid Build Coastguard Worker            # Comparing for a literal zero rather than the scalar value zero
358*6236dae4SAndroid Build Coastguard Worker            # covers the case where $scope contains the ending '*' from the
359*6236dae4SAndroid Build Coastguard Worker            # comment. If we use a scalar comparison (==) we induce warnings
360*6236dae4SAndroid Build Coastguard Worker            # on non-scalar contents.
361*6236dae4SAndroid Build Coastguard Worker            if($scope eq "0") {
362*6236dae4SAndroid Build Coastguard Worker                checkwarn("BADCOMMAND",
363*6236dae4SAndroid Build Coastguard Worker                          $line, 0, $file, $l,
364*6236dae4SAndroid Build Coastguard Worker                          "Disable zero not supported, did you mean to enable?");
365*6236dae4SAndroid Build Coastguard Worker            }
366*6236dae4SAndroid Build Coastguard Worker            elsif($ignore_set{$warn}) {
367*6236dae4SAndroid Build Coastguard Worker                checkwarn("BADCOMMAND",
368*6236dae4SAndroid Build Coastguard Worker                          $line, 0, $file, $l,
369*6236dae4SAndroid Build Coastguard Worker                          "$warn already disabled from line $ignore_set{$warn}");
370*6236dae4SAndroid Build Coastguard Worker            }
371*6236dae4SAndroid Build Coastguard Worker            else {
372*6236dae4SAndroid Build Coastguard Worker                $ignore{$warn}=$scope;
373*6236dae4SAndroid Build Coastguard Worker                $ignore_set{$warn}=$line;
374*6236dae4SAndroid Build Coastguard Worker                $ignore_line[$line]=$l;
375*6236dae4SAndroid Build Coastguard Worker            }
376*6236dae4SAndroid Build Coastguard Worker        }
377*6236dae4SAndroid Build Coastguard Worker        elsif($enable eq "enable") {
378*6236dae4SAndroid Build Coastguard Worker            enable_warn($what, $line, $file, $l);
379*6236dae4SAndroid Build Coastguard Worker        }
380*6236dae4SAndroid Build Coastguard Worker        else {
381*6236dae4SAndroid Build Coastguard Worker            checkwarn("BADCOMMAND",
382*6236dae4SAndroid Build Coastguard Worker                      $line, 0, $file, $l,
383*6236dae4SAndroid Build Coastguard Worker                      "Illegal !checksrc! command");
384*6236dae4SAndroid Build Coastguard Worker        }
385*6236dae4SAndroid Build Coastguard Worker    }
386*6236dae4SAndroid Build Coastguard Worker}
387*6236dae4SAndroid Build Coastguard Worker
388*6236dae4SAndroid Build Coastguard Workersub nostrings {
389*6236dae4SAndroid Build Coastguard Worker    my ($str) = @_;
390*6236dae4SAndroid Build Coastguard Worker    $str =~ s/\".*\"//g;
391*6236dae4SAndroid Build Coastguard Worker    return $str;
392*6236dae4SAndroid Build Coastguard Worker}
393*6236dae4SAndroid Build Coastguard Worker
394*6236dae4SAndroid Build Coastguard Workersub scanfile {
395*6236dae4SAndroid Build Coastguard Worker    my ($file) = @_;
396*6236dae4SAndroid Build Coastguard Worker
397*6236dae4SAndroid Build Coastguard Worker    my $line = 1;
398*6236dae4SAndroid Build Coastguard Worker    my $prevl="";
399*6236dae4SAndroid Build Coastguard Worker    my $prevpl="";
400*6236dae4SAndroid Build Coastguard Worker    my $l = "";
401*6236dae4SAndroid Build Coastguard Worker    my $prep = 0;
402*6236dae4SAndroid Build Coastguard Worker    my $prevp = 0;
403*6236dae4SAndroid Build Coastguard Worker    open(my $R, '<', $file) || die "failed to open $file";
404*6236dae4SAndroid Build Coastguard Worker
405*6236dae4SAndroid Build Coastguard Worker    my $incomment=0;
406*6236dae4SAndroid Build Coastguard Worker    my @copyright=();
407*6236dae4SAndroid Build Coastguard Worker    my %includes;
408*6236dae4SAndroid Build Coastguard Worker    checksrc_clear(); # for file based ignores
409*6236dae4SAndroid Build Coastguard Worker    accept_violations();
410*6236dae4SAndroid Build Coastguard Worker
411*6236dae4SAndroid Build Coastguard Worker    while(<$R>) {
412*6236dae4SAndroid Build Coastguard Worker        $windows_os ? $_ =~ s/\r?\n$// : chomp;
413*6236dae4SAndroid Build Coastguard Worker        my $l = $_;
414*6236dae4SAndroid Build Coastguard Worker        my $ol = $l; # keep the unmodified line for error reporting
415*6236dae4SAndroid Build Coastguard Worker        my $column = 0;
416*6236dae4SAndroid Build Coastguard Worker
417*6236dae4SAndroid Build Coastguard Worker        # check for !checksrc! commands
418*6236dae4SAndroid Build Coastguard Worker        if($l =~ /\!checksrc\! (.*)/) {
419*6236dae4SAndroid Build Coastguard Worker            my $cmd = $1;
420*6236dae4SAndroid Build Coastguard Worker            checksrc($cmd, $line, $file, $l)
421*6236dae4SAndroid Build Coastguard Worker        }
422*6236dae4SAndroid Build Coastguard Worker
423*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^#line (\d+) \"([^\"]*)\"/) {
424*6236dae4SAndroid Build Coastguard Worker            # a #line instruction
425*6236dae4SAndroid Build Coastguard Worker            $file = $2;
426*6236dae4SAndroid Build Coastguard Worker            $line = $1;
427*6236dae4SAndroid Build Coastguard Worker            next;
428*6236dae4SAndroid Build Coastguard Worker        }
429*6236dae4SAndroid Build Coastguard Worker
430*6236dae4SAndroid Build Coastguard Worker        # check for a copyright statement and save the years
431*6236dae4SAndroid Build Coastguard Worker        if($l =~ /\* +copyright .* (\d\d\d\d|)/i) {
432*6236dae4SAndroid Build Coastguard Worker            my $count = 0;
433*6236dae4SAndroid Build Coastguard Worker            while($l =~ /([\d]{4})/g) {
434*6236dae4SAndroid Build Coastguard Worker                push @copyright, {
435*6236dae4SAndroid Build Coastguard Worker                  year => $1,
436*6236dae4SAndroid Build Coastguard Worker                  line => $line,
437*6236dae4SAndroid Build Coastguard Worker                  col => index($l, $1),
438*6236dae4SAndroid Build Coastguard Worker                  code => $l
439*6236dae4SAndroid Build Coastguard Worker                };
440*6236dae4SAndroid Build Coastguard Worker                $count++;
441*6236dae4SAndroid Build Coastguard Worker            }
442*6236dae4SAndroid Build Coastguard Worker            if(!$count) {
443*6236dae4SAndroid Build Coastguard Worker                # year-less
444*6236dae4SAndroid Build Coastguard Worker                push @copyright, {
445*6236dae4SAndroid Build Coastguard Worker                    year => -1,
446*6236dae4SAndroid Build Coastguard Worker                    line => $line,
447*6236dae4SAndroid Build Coastguard Worker                    col => index($l, $1),
448*6236dae4SAndroid Build Coastguard Worker                    code => $l
449*6236dae4SAndroid Build Coastguard Worker                };
450*6236dae4SAndroid Build Coastguard Worker            }
451*6236dae4SAndroid Build Coastguard Worker        }
452*6236dae4SAndroid Build Coastguard Worker
453*6236dae4SAndroid Build Coastguard Worker        # detect long lines
454*6236dae4SAndroid Build Coastguard Worker        if(length($l) > $max_column) {
455*6236dae4SAndroid Build Coastguard Worker            checkwarn("LONGLINE", $line, length($l), $file, $l,
456*6236dae4SAndroid Build Coastguard Worker                      "Longer than $max_column columns");
457*6236dae4SAndroid Build Coastguard Worker        }
458*6236dae4SAndroid Build Coastguard Worker        # detect TAB characters
459*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)\t/) {
460*6236dae4SAndroid Build Coastguard Worker            checkwarn("TABS",
461*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $l, "Contains TAB character", 1);
462*6236dae4SAndroid Build Coastguard Worker        }
463*6236dae4SAndroid Build Coastguard Worker        # detect trailing whitespace
464*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)[ \t]+\z/) {
465*6236dae4SAndroid Build Coastguard Worker            checkwarn("TRAILINGSPACE",
466*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $l, "Trailing whitespace");
467*6236dae4SAndroid Build Coastguard Worker        }
468*6236dae4SAndroid Build Coastguard Worker
469*6236dae4SAndroid Build Coastguard Worker        # no space after comment start
470*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)\/\*\w/) {
471*6236dae4SAndroid Build Coastguard Worker            checkwarn("COMMENTNOSPACESTART",
472*6236dae4SAndroid Build Coastguard Worker                      $line, length($1) + 2, $file, $l,
473*6236dae4SAndroid Build Coastguard Worker                      "Missing space after comment start");
474*6236dae4SAndroid Build Coastguard Worker        }
475*6236dae4SAndroid Build Coastguard Worker        # no space at comment end
476*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)\w\*\//) {
477*6236dae4SAndroid Build Coastguard Worker            checkwarn("COMMENTNOSPACEEND",
478*6236dae4SAndroid Build Coastguard Worker                      $line, length($1) + 1, $file, $l,
479*6236dae4SAndroid Build Coastguard Worker                      "Missing space end comment end");
480*6236dae4SAndroid Build Coastguard Worker        }
481*6236dae4SAndroid Build Coastguard Worker        # ------------------------------------------------------------
482*6236dae4SAndroid Build Coastguard Worker        # Above this marker, the checks were done on lines *including*
483*6236dae4SAndroid Build Coastguard Worker        # comments
484*6236dae4SAndroid Build Coastguard Worker        # ------------------------------------------------------------
485*6236dae4SAndroid Build Coastguard Worker
486*6236dae4SAndroid Build Coastguard Worker        # strip off C89 comments
487*6236dae4SAndroid Build Coastguard Worker
488*6236dae4SAndroid Build Coastguard Worker      comment:
489*6236dae4SAndroid Build Coastguard Worker        if(!$incomment) {
490*6236dae4SAndroid Build Coastguard Worker            if($l =~ s/\/\*.*\*\// /g) {
491*6236dae4SAndroid Build Coastguard Worker                # full /* comments */ were removed!
492*6236dae4SAndroid Build Coastguard Worker            }
493*6236dae4SAndroid Build Coastguard Worker            if($l =~ s/\/\*.*//) {
494*6236dae4SAndroid Build Coastguard Worker                # start of /* comment was removed
495*6236dae4SAndroid Build Coastguard Worker                $incomment = 1;
496*6236dae4SAndroid Build Coastguard Worker            }
497*6236dae4SAndroid Build Coastguard Worker        }
498*6236dae4SAndroid Build Coastguard Worker        else {
499*6236dae4SAndroid Build Coastguard Worker            if($l =~ s/.*\*\///) {
500*6236dae4SAndroid Build Coastguard Worker                # end of comment */ was removed
501*6236dae4SAndroid Build Coastguard Worker                $incomment = 0;
502*6236dae4SAndroid Build Coastguard Worker                goto comment;
503*6236dae4SAndroid Build Coastguard Worker            }
504*6236dae4SAndroid Build Coastguard Worker            else {
505*6236dae4SAndroid Build Coastguard Worker                # still within a comment
506*6236dae4SAndroid Build Coastguard Worker                $l="";
507*6236dae4SAndroid Build Coastguard Worker            }
508*6236dae4SAndroid Build Coastguard Worker        }
509*6236dae4SAndroid Build Coastguard Worker
510*6236dae4SAndroid Build Coastguard Worker        # ------------------------------------------------------------
511*6236dae4SAndroid Build Coastguard Worker        # Below this marker, the checks were done on lines *without*
512*6236dae4SAndroid Build Coastguard Worker        # comments
513*6236dae4SAndroid Build Coastguard Worker        # ------------------------------------------------------------
514*6236dae4SAndroid Build Coastguard Worker
515*6236dae4SAndroid Build Coastguard Worker        # prev line was a preprocessor **and** ended with a backslash
516*6236dae4SAndroid Build Coastguard Worker        if($prep && ($prevpl =~ /\\ *\z/)) {
517*6236dae4SAndroid Build Coastguard Worker            # this is still a preprocessor line
518*6236dae4SAndroid Build Coastguard Worker            $prep = 1;
519*6236dae4SAndroid Build Coastguard Worker            goto preproc;
520*6236dae4SAndroid Build Coastguard Worker        }
521*6236dae4SAndroid Build Coastguard Worker        $prep = 0;
522*6236dae4SAndroid Build Coastguard Worker
523*6236dae4SAndroid Build Coastguard Worker        # crude attempt to detect // comments without too many false
524*6236dae4SAndroid Build Coastguard Worker        # positives
525*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(([^"\*]*)[^:"]|)\/\//) {
526*6236dae4SAndroid Build Coastguard Worker            checkwarn("CPPCOMMENTS",
527*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $l, "\/\/ comment");
528*6236dae4SAndroid Build Coastguard Worker        }
529*6236dae4SAndroid Build Coastguard Worker
530*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(\#\s*include\s+)([\">].*[>}"])/) {
531*6236dae4SAndroid Build Coastguard Worker            my ($pre, $path) = ($1, $2);
532*6236dae4SAndroid Build Coastguard Worker            if($includes{$path}) {
533*6236dae4SAndroid Build Coastguard Worker                checkwarn("INCLUDEDUP",
534*6236dae4SAndroid Build Coastguard Worker                          $line, length($1), $file, $l, "duplicated include");
535*6236dae4SAndroid Build Coastguard Worker            }
536*6236dae4SAndroid Build Coastguard Worker            $includes{$path} = $l;
537*6236dae4SAndroid Build Coastguard Worker        }
538*6236dae4SAndroid Build Coastguard Worker
539*6236dae4SAndroid Build Coastguard Worker        # detect and strip preprocessor directives
540*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^[ \t]*\#/) {
541*6236dae4SAndroid Build Coastguard Worker            # preprocessor line
542*6236dae4SAndroid Build Coastguard Worker            $prep = 1;
543*6236dae4SAndroid Build Coastguard Worker            goto preproc;
544*6236dae4SAndroid Build Coastguard Worker        }
545*6236dae4SAndroid Build Coastguard Worker
546*6236dae4SAndroid Build Coastguard Worker        my $nostr = nostrings($l);
547*6236dae4SAndroid Build Coastguard Worker        # check spaces after for/if/while/function call
548*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)(for|if|while|switch| ([a-zA-Z0-9_]+)) \((.)/) {
549*6236dae4SAndroid Build Coastguard Worker            my ($leading, $word, $extra, $first)=($1,$2,$3,$4);
550*6236dae4SAndroid Build Coastguard Worker            if($1 =~ / *\#/) {
551*6236dae4SAndroid Build Coastguard Worker                # this is a #if, treat it differently
552*6236dae4SAndroid Build Coastguard Worker            }
553*6236dae4SAndroid Build Coastguard Worker            elsif(defined $3 && $3 eq "return") {
554*6236dae4SAndroid Build Coastguard Worker                # return must have a space
555*6236dae4SAndroid Build Coastguard Worker            }
556*6236dae4SAndroid Build Coastguard Worker            elsif(defined $3 && $3 eq "case") {
557*6236dae4SAndroid Build Coastguard Worker                # case must have a space
558*6236dae4SAndroid Build Coastguard Worker            }
559*6236dae4SAndroid Build Coastguard Worker            elsif(($first eq "*") && ($word !~ /(for|if|while|switch)/)) {
560*6236dae4SAndroid Build Coastguard Worker                # A "(*" beginning makes the space OK because it wants to
561*6236dae4SAndroid Build Coastguard Worker                # allow function pointer declared
562*6236dae4SAndroid Build Coastguard Worker            }
563*6236dae4SAndroid Build Coastguard Worker            elsif($1 =~ / *typedef/) {
564*6236dae4SAndroid Build Coastguard Worker                # typedefs can use space-paren
565*6236dae4SAndroid Build Coastguard Worker            }
566*6236dae4SAndroid Build Coastguard Worker            else {
567*6236dae4SAndroid Build Coastguard Worker                checkwarn("SPACEBEFOREPAREN", $line, length($leading)+length($word), $file, $l,
568*6236dae4SAndroid Build Coastguard Worker                          "$word with space");
569*6236dae4SAndroid Build Coastguard Worker            }
570*6236dae4SAndroid Build Coastguard Worker        }
571*6236dae4SAndroid Build Coastguard Worker        # check for '== NULL' in if/while conditions but not if the thing on
572*6236dae4SAndroid Build Coastguard Worker        # the left of it is a function call
573*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)(if|while)(\(.*?)([!=]= NULL|NULL [!=]=)/) {
574*6236dae4SAndroid Build Coastguard Worker            checkwarn("EQUALSNULL", $line,
575*6236dae4SAndroid Build Coastguard Worker                      length($1) + length($2) + length($3),
576*6236dae4SAndroid Build Coastguard Worker                      $file, $l, "we prefer !variable instead of \"== NULL\" comparisons");
577*6236dae4SAndroid Build Coastguard Worker        }
578*6236dae4SAndroid Build Coastguard Worker
579*6236dae4SAndroid Build Coastguard Worker        # check for '!= 0' in if/while conditions but not if the thing on
580*6236dae4SAndroid Build Coastguard Worker        # the left of it is a function call
581*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)(if|while)(\(.*[^)]) != 0[^x]/) {
582*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOTEQUALSZERO", $line,
583*6236dae4SAndroid Build Coastguard Worker                      length($1) + length($2) + length($3),
584*6236dae4SAndroid Build Coastguard Worker                      $file, $l, "we prefer if(rc) instead of \"rc != 0\" comparisons");
585*6236dae4SAndroid Build Coastguard Worker        }
586*6236dae4SAndroid Build Coastguard Worker
587*6236dae4SAndroid Build Coastguard Worker        # check spaces in 'do {'
588*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^( *)do( *)\{/ && length($2) != 1) {
589*6236dae4SAndroid Build Coastguard Worker            checkwarn("DOBRACE", $line, length($1) + 2, $file, $l, "one space after do before brace");
590*6236dae4SAndroid Build Coastguard Worker        }
591*6236dae4SAndroid Build Coastguard Worker        # check spaces in 'do {'
592*6236dae4SAndroid Build Coastguard Worker        elsif($nostr =~ /^( *)\}( *)while/ && length($2) != 1) {
593*6236dae4SAndroid Build Coastguard Worker            checkwarn("BRACEWHILE", $line, length($1) + 2, $file, $l, "one space between brace and while");
594*6236dae4SAndroid Build Coastguard Worker        }
595*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^((.*\s)(if) *\()(.*)\)(.*)/) {
596*6236dae4SAndroid Build Coastguard Worker            my $pos = length($1);
597*6236dae4SAndroid Build Coastguard Worker            my $postparen = $5;
598*6236dae4SAndroid Build Coastguard Worker            my $cond = $4;
599*6236dae4SAndroid Build Coastguard Worker            if($cond =~ / = /) {
600*6236dae4SAndroid Build Coastguard Worker                checkwarn("ASSIGNWITHINCONDITION",
601*6236dae4SAndroid Build Coastguard Worker                          $line, $pos+1, $file, $l,
602*6236dae4SAndroid Build Coastguard Worker                          "assignment within conditional expression");
603*6236dae4SAndroid Build Coastguard Worker            }
604*6236dae4SAndroid Build Coastguard Worker            my $temp = $cond;
605*6236dae4SAndroid Build Coastguard Worker            $temp =~ s/\(//g; # remove open parens
606*6236dae4SAndroid Build Coastguard Worker            my $openc = length($cond) - length($temp);
607*6236dae4SAndroid Build Coastguard Worker
608*6236dae4SAndroid Build Coastguard Worker            $temp = $cond;
609*6236dae4SAndroid Build Coastguard Worker            $temp =~ s/\)//g; # remove close parens
610*6236dae4SAndroid Build Coastguard Worker            my $closec = length($cond) - length($temp);
611*6236dae4SAndroid Build Coastguard Worker            my $even = $openc == $closec;
612*6236dae4SAndroid Build Coastguard Worker
613*6236dae4SAndroid Build Coastguard Worker            if($l =~ / *\#/) {
614*6236dae4SAndroid Build Coastguard Worker                # this is a #if, treat it differently
615*6236dae4SAndroid Build Coastguard Worker            }
616*6236dae4SAndroid Build Coastguard Worker            elsif($even && $postparen &&
617*6236dae4SAndroid Build Coastguard Worker               ($postparen !~ /^ *$/) && ($postparen !~ /^ *[,{&|\\]+/)) {
618*6236dae4SAndroid Build Coastguard Worker                checkwarn("ONELINECONDITION",
619*6236dae4SAndroid Build Coastguard Worker                          $line, length($l)-length($postparen), $file, $l,
620*6236dae4SAndroid Build Coastguard Worker                          "conditional block on the same line");
621*6236dae4SAndroid Build Coastguard Worker            }
622*6236dae4SAndroid Build Coastguard Worker        }
623*6236dae4SAndroid Build Coastguard Worker        # check spaces after open parentheses
624*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*[a-z])\( /i) {
625*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACEAFTERPAREN",
626*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
627*6236dae4SAndroid Build Coastguard Worker                      "space after open parenthesis");
628*6236dae4SAndroid Build Coastguard Worker        }
629*6236dae4SAndroid Build Coastguard Worker
630*6236dae4SAndroid Build Coastguard Worker        # check spaces before Logical AND operator
631*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)\w&&/i) {
632*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACEAND",
633*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
634*6236dae4SAndroid Build Coastguard Worker                      "missing space before Logical AND");
635*6236dae4SAndroid Build Coastguard Worker        }
636*6236dae4SAndroid Build Coastguard Worker
637*6236dae4SAndroid Build Coastguard Worker        # check spaces after Logical AND operator
638*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*&&)\w/i) {
639*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACEAND",
640*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $l,
641*6236dae4SAndroid Build Coastguard Worker                      "missing space after Logical AND");
642*6236dae4SAndroid Build Coastguard Worker        }
643*6236dae4SAndroid Build Coastguard Worker
644*6236dae4SAndroid Build Coastguard Worker        # check spaces before colon
645*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*[^']\?[^'].*)(\w|\)|\]|')\:/i) {
646*6236dae4SAndroid Build Coastguard Worker            my $m = $1;
647*6236dae4SAndroid Build Coastguard Worker            my $e = $nostr;
648*6236dae4SAndroid Build Coastguard Worker            $e =~ s/'(.)':'(.)'/$1:$2/g; # eliminate chars quotes that surround colon
649*6236dae4SAndroid Build Coastguard Worker            $e =~ s/':'//g;              # ignore these
650*6236dae4SAndroid Build Coastguard Worker            if($e =~ /^(.*[^']\?[^'].*)(\w|\)|\]|')\:/i) {
651*6236dae4SAndroid Build Coastguard Worker                checkwarn("NOSPACEC",
652*6236dae4SAndroid Build Coastguard Worker                          $line, length($m)+1, $file, $l,
653*6236dae4SAndroid Build Coastguard Worker                          "missing space before colon");
654*6236dae4SAndroid Build Coastguard Worker            }
655*6236dae4SAndroid Build Coastguard Worker        }
656*6236dae4SAndroid Build Coastguard Worker        # check spaces after colon
657*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*[^'"]\?[^'"].*)\:(\w|\)|\]|')/i) {
658*6236dae4SAndroid Build Coastguard Worker            my $m = $1;
659*6236dae4SAndroid Build Coastguard Worker            my $e = $nostr;
660*6236dae4SAndroid Build Coastguard Worker            $e =~ s/'(.)':'(.)'/$1:$2/g; # eliminate chars quotes that surround colon
661*6236dae4SAndroid Build Coastguard Worker            $e =~ s/':'//g;              # ignore these
662*6236dae4SAndroid Build Coastguard Worker            if($e =~ /^(.*[^'"]\?[^'"].*)\:(\w|\)|\]|')/i) {
663*6236dae4SAndroid Build Coastguard Worker                checkwarn("NOSPACEC",
664*6236dae4SAndroid Build Coastguard Worker                          $line, length($m)+1, $file, $l,
665*6236dae4SAndroid Build Coastguard Worker                          "missing space after colon");
666*6236dae4SAndroid Build Coastguard Worker            }
667*6236dae4SAndroid Build Coastguard Worker        }
668*6236dae4SAndroid Build Coastguard Worker
669*6236dae4SAndroid Build Coastguard Worker        # check spaces before question mark
670*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)(\w|\)|\]|')\?/i) {
671*6236dae4SAndroid Build Coastguard Worker            my $m = $1;
672*6236dae4SAndroid Build Coastguard Worker            my $e = $nostr;
673*6236dae4SAndroid Build Coastguard Worker            $e =~ s/'?'//g; # ignore these
674*6236dae4SAndroid Build Coastguard Worker            if($e =~ /^(.*)(\w|\)|\]|')\?/i) {
675*6236dae4SAndroid Build Coastguard Worker                checkwarn("NOSPACEQ",
676*6236dae4SAndroid Build Coastguard Worker                          $line, length($m)+1, $file, $l,
677*6236dae4SAndroid Build Coastguard Worker                          "missing space before question mark");
678*6236dae4SAndroid Build Coastguard Worker            }
679*6236dae4SAndroid Build Coastguard Worker        }
680*6236dae4SAndroid Build Coastguard Worker        # check spaces after question mark
681*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)\?\w/i) {
682*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACEQ",
683*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
684*6236dae4SAndroid Build Coastguard Worker                      "missing space after question mark");
685*6236dae4SAndroid Build Coastguard Worker        }
686*6236dae4SAndroid Build Coastguard Worker
687*6236dae4SAndroid Build Coastguard Worker        # check spaces before less or greater than
688*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)(\w|\)|\])[<>]/) {
689*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACETHAN",
690*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
691*6236dae4SAndroid Build Coastguard Worker                      "missing space before less or greater than");
692*6236dae4SAndroid Build Coastguard Worker        }
693*6236dae4SAndroid Build Coastguard Worker        # check spaces after less or greater than
694*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)[^-][<>](\w|\(|\[)/) {
695*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACETHAN",
696*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
697*6236dae4SAndroid Build Coastguard Worker                      "missing space after less or greater than");
698*6236dae4SAndroid Build Coastguard Worker        }
699*6236dae4SAndroid Build Coastguard Worker
700*6236dae4SAndroid Build Coastguard Worker        # check spaces before close parentheses, unless it was a space or a
701*6236dae4SAndroid Build Coastguard Worker        # close parenthesis!
702*6236dae4SAndroid Build Coastguard Worker        if($l =~ /(.*[^\) ]) \)/) {
703*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACEBEFORECLOSE",
704*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
705*6236dae4SAndroid Build Coastguard Worker                      "space before close parenthesis");
706*6236dae4SAndroid Build Coastguard Worker        }
707*6236dae4SAndroid Build Coastguard Worker
708*6236dae4SAndroid Build Coastguard Worker        # check spaces before comma!
709*6236dae4SAndroid Build Coastguard Worker        if($l =~ /(.*[^ ]) ,/) {
710*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACEBEFORECOMMA",
711*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l,
712*6236dae4SAndroid Build Coastguard Worker                      "space before comma");
713*6236dae4SAndroid Build Coastguard Worker        }
714*6236dae4SAndroid Build Coastguard Worker
715*6236dae4SAndroid Build Coastguard Worker        # check for "return(" without space
716*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)return\(/) {
717*6236dae4SAndroid Build Coastguard Worker            if($1 =~ / *\#/) {
718*6236dae4SAndroid Build Coastguard Worker                # this is a #if, treat it differently
719*6236dae4SAndroid Build Coastguard Worker            }
720*6236dae4SAndroid Build Coastguard Worker            else {
721*6236dae4SAndroid Build Coastguard Worker                checkwarn("RETURNNOSPACE", $line, length($1)+6, $file, $l,
722*6236dae4SAndroid Build Coastguard Worker                          "return without space before paren");
723*6236dae4SAndroid Build Coastguard Worker            }
724*6236dae4SAndroid Build Coastguard Worker        }
725*6236dae4SAndroid Build Coastguard Worker
726*6236dae4SAndroid Build Coastguard Worker        # check for "sizeof" without parenthesis
727*6236dae4SAndroid Build Coastguard Worker        if(($l =~ /^(.*)sizeof *([ (])/) && ($2 ne "(")) {
728*6236dae4SAndroid Build Coastguard Worker            if($1 =~ / *\#/) {
729*6236dae4SAndroid Build Coastguard Worker                # this is a #if, treat it differently
730*6236dae4SAndroid Build Coastguard Worker            }
731*6236dae4SAndroid Build Coastguard Worker            else {
732*6236dae4SAndroid Build Coastguard Worker                checkwarn("SIZEOFNOPAREN", $line, length($1)+6, $file, $l,
733*6236dae4SAndroid Build Coastguard Worker                          "sizeof without parenthesis");
734*6236dae4SAndroid Build Coastguard Worker            }
735*6236dae4SAndroid Build Coastguard Worker        }
736*6236dae4SAndroid Build Coastguard Worker
737*6236dae4SAndroid Build Coastguard Worker        # check for comma without space
738*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*),[^ \n]/) {
739*6236dae4SAndroid Build Coastguard Worker            my $pref=$1;
740*6236dae4SAndroid Build Coastguard Worker            my $ign=0;
741*6236dae4SAndroid Build Coastguard Worker            if($pref =~ / *\#/) {
742*6236dae4SAndroid Build Coastguard Worker                # this is a #if, treat it differently
743*6236dae4SAndroid Build Coastguard Worker                $ign=1;
744*6236dae4SAndroid Build Coastguard Worker            }
745*6236dae4SAndroid Build Coastguard Worker            elsif($pref =~ /\/\*/) {
746*6236dae4SAndroid Build Coastguard Worker                # this is a comment
747*6236dae4SAndroid Build Coastguard Worker                $ign=1;
748*6236dae4SAndroid Build Coastguard Worker            }
749*6236dae4SAndroid Build Coastguard Worker            elsif($pref =~ /[\"\']/) {
750*6236dae4SAndroid Build Coastguard Worker                $ign = 1;
751*6236dae4SAndroid Build Coastguard Worker                # There is a quote here, figure out whether the comma is
752*6236dae4SAndroid Build Coastguard Worker                # within a string or '' or not.
753*6236dae4SAndroid Build Coastguard Worker                if($pref =~ /\"/) {
754*6236dae4SAndroid Build Coastguard Worker                    # within a string
755*6236dae4SAndroid Build Coastguard Worker                }
756*6236dae4SAndroid Build Coastguard Worker                elsif($pref =~ /\'$/) {
757*6236dae4SAndroid Build Coastguard Worker                    # a single letter
758*6236dae4SAndroid Build Coastguard Worker                }
759*6236dae4SAndroid Build Coastguard Worker                else {
760*6236dae4SAndroid Build Coastguard Worker                    $ign = 0;
761*6236dae4SAndroid Build Coastguard Worker                }
762*6236dae4SAndroid Build Coastguard Worker            }
763*6236dae4SAndroid Build Coastguard Worker            if(!$ign) {
764*6236dae4SAndroid Build Coastguard Worker                checkwarn("COMMANOSPACE", $line, length($pref)+1, $file, $l,
765*6236dae4SAndroid Build Coastguard Worker                          "comma without following space");
766*6236dae4SAndroid Build Coastguard Worker            }
767*6236dae4SAndroid Build Coastguard Worker        }
768*6236dae4SAndroid Build Coastguard Worker
769*6236dae4SAndroid Build Coastguard Worker        # check for "} else"
770*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)\} *else/) {
771*6236dae4SAndroid Build Coastguard Worker            checkwarn("BRACEELSE",
772*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $l, "else after closing brace on same line");
773*6236dae4SAndroid Build Coastguard Worker        }
774*6236dae4SAndroid Build Coastguard Worker        # check for "){"
775*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*)\)\{/) {
776*6236dae4SAndroid Build Coastguard Worker            checkwarn("PARENBRACE",
777*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $l, "missing space after close paren");
778*6236dae4SAndroid Build Coastguard Worker        }
779*6236dae4SAndroid Build Coastguard Worker        # check for "^{" with an empty line before it
780*6236dae4SAndroid Build Coastguard Worker        if(($l =~ /^\{/) && ($prevl =~ /^[ \t]*\z/)) {
781*6236dae4SAndroid Build Coastguard Worker            checkwarn("EMPTYLINEBRACE",
782*6236dae4SAndroid Build Coastguard Worker                      $line, 0, $file, $l, "empty line before open brace");
783*6236dae4SAndroid Build Coastguard Worker        }
784*6236dae4SAndroid Build Coastguard Worker
785*6236dae4SAndroid Build Coastguard Worker        # check for space before the semicolon last in a line
786*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*[^ ].*) ;$/) {
787*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACESEMICOLON",
788*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol, "no space before semicolon");
789*6236dae4SAndroid Build Coastguard Worker        }
790*6236dae4SAndroid Build Coastguard Worker
791*6236dae4SAndroid Build Coastguard Worker        # check for space before the colon in a switch label
792*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^( *(case .+|default)) :/) {
793*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACESWITCHCOLON",
794*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol, "no space before colon of switch label");
795*6236dae4SAndroid Build Coastguard Worker        }
796*6236dae4SAndroid Build Coastguard Worker
797*6236dae4SAndroid Build Coastguard Worker        if($prevl !~ /\?\z/ && $l =~ /^ +([A-Za-z_][A-Za-z0-9_]*):$/ && $1 ne 'default') {
798*6236dae4SAndroid Build Coastguard Worker            checkwarn("SPACEBEFORELABEL",
799*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol, "no space before label");
800*6236dae4SAndroid Build Coastguard Worker        }
801*6236dae4SAndroid Build Coastguard Worker
802*6236dae4SAndroid Build Coastguard Worker        # scan for use of banned functions
803*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*\W)
804*6236dae4SAndroid Build Coastguard Worker                   (gmtime|localtime|
805*6236dae4SAndroid Build Coastguard Worker                    gets|
806*6236dae4SAndroid Build Coastguard Worker                    strtok|
807*6236dae4SAndroid Build Coastguard Worker                    v?sprintf|
808*6236dae4SAndroid Build Coastguard Worker                    (str|_mbs|_tcs|_wcs)n?cat|
809*6236dae4SAndroid Build Coastguard Worker                    LoadLibrary(Ex)?(A|W)?|
810*6236dae4SAndroid Build Coastguard Worker                    _?w?access)
811*6236dae4SAndroid Build Coastguard Worker                   \s*\(
812*6236dae4SAndroid Build Coastguard Worker                 /x) {
813*6236dae4SAndroid Build Coastguard Worker            checkwarn("BANNEDFUNC",
814*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol,
815*6236dae4SAndroid Build Coastguard Worker                      "use of $2 is banned");
816*6236dae4SAndroid Build Coastguard Worker        }
817*6236dae4SAndroid Build Coastguard Worker        if($warnings{"STRERROR"}) {
818*6236dae4SAndroid Build Coastguard Worker            # scan for use of banned strerror. This is not a BANNEDFUNC to
819*6236dae4SAndroid Build Coastguard Worker            # allow for individual enable/disable of this warning.
820*6236dae4SAndroid Build Coastguard Worker            if($l =~ /^(.*\W)(strerror)\s*\(/x) {
821*6236dae4SAndroid Build Coastguard Worker                if($1 !~ /^ *\#/) {
822*6236dae4SAndroid Build Coastguard Worker                    # skip preprocessor lines
823*6236dae4SAndroid Build Coastguard Worker                    checkwarn("STRERROR",
824*6236dae4SAndroid Build Coastguard Worker                              $line, length($1), $file, $ol,
825*6236dae4SAndroid Build Coastguard Worker                              "use of $2 is banned");
826*6236dae4SAndroid Build Coastguard Worker                }
827*6236dae4SAndroid Build Coastguard Worker            }
828*6236dae4SAndroid Build Coastguard Worker        }
829*6236dae4SAndroid Build Coastguard Worker        if($warnings{"STRNCPY"}) {
830*6236dae4SAndroid Build Coastguard Worker            # scan for use of banned strncpy. This is not a BANNEDFUNC to
831*6236dae4SAndroid Build Coastguard Worker            # allow for individual enable/disable of this warning.
832*6236dae4SAndroid Build Coastguard Worker            if($l =~ /^(.*\W)(strncpy)\s*\(/x) {
833*6236dae4SAndroid Build Coastguard Worker                if($1 !~ /^ *\#/) {
834*6236dae4SAndroid Build Coastguard Worker                    # skip preprocessor lines
835*6236dae4SAndroid Build Coastguard Worker                    checkwarn("STRNCPY",
836*6236dae4SAndroid Build Coastguard Worker                              $line, length($1), $file, $ol,
837*6236dae4SAndroid Build Coastguard Worker                              "use of $2 is banned");
838*6236dae4SAndroid Build Coastguard Worker                }
839*6236dae4SAndroid Build Coastguard Worker            }
840*6236dae4SAndroid Build Coastguard Worker        }
841*6236dae4SAndroid Build Coastguard Worker        if($warnings{"STDERR"}) {
842*6236dae4SAndroid Build Coastguard Worker            # scan for use of banned stderr. This is not a BANNEDFUNC to
843*6236dae4SAndroid Build Coastguard Worker            # allow for individual enable/disable of this warning.
844*6236dae4SAndroid Build Coastguard Worker            if($l =~ /^([^\"-]*\W)(stderr)[^\"_]/x) {
845*6236dae4SAndroid Build Coastguard Worker                if($1 !~ /^ *\#/) {
846*6236dae4SAndroid Build Coastguard Worker                    # skip preprocessor lines
847*6236dae4SAndroid Build Coastguard Worker                    checkwarn("STDERR",
848*6236dae4SAndroid Build Coastguard Worker                              $line, length($1), $file, $ol,
849*6236dae4SAndroid Build Coastguard Worker                              "use of $2 is banned (use tool_stderr instead)");
850*6236dae4SAndroid Build Coastguard Worker                }
851*6236dae4SAndroid Build Coastguard Worker            }
852*6236dae4SAndroid Build Coastguard Worker        }
853*6236dae4SAndroid Build Coastguard Worker        # scan for use of snprintf for curl-internals reasons
854*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) {
855*6236dae4SAndroid Build Coastguard Worker            checkwarn("SNPRINTF",
856*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol,
857*6236dae4SAndroid Build Coastguard Worker                      "use of $2 is banned");
858*6236dae4SAndroid Build Coastguard Worker        }
859*6236dae4SAndroid Build Coastguard Worker
860*6236dae4SAndroid Build Coastguard Worker        # scan for use of non-binary fopen without the macro
861*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) {
862*6236dae4SAndroid Build Coastguard Worker            my $mode = $2;
863*6236dae4SAndroid Build Coastguard Worker            if($mode !~ /b/) {
864*6236dae4SAndroid Build Coastguard Worker                checkwarn("FOPENMODE",
865*6236dae4SAndroid Build Coastguard Worker                          $line, length($1), $file, $ol,
866*6236dae4SAndroid Build Coastguard Worker                          "use of non-binary fopen without FOPEN_* macro: $mode");
867*6236dae4SAndroid Build Coastguard Worker            }
868*6236dae4SAndroid Build Coastguard Worker        }
869*6236dae4SAndroid Build Coastguard Worker
870*6236dae4SAndroid Build Coastguard Worker        # check for open brace first on line but not first column only alert
871*6236dae4SAndroid Build Coastguard Worker        # if previous line ended with a close paren and it wasn't a cpp line
872*6236dae4SAndroid Build Coastguard Worker        if(($prevl =~ /\)\z/) && ($l =~ /^( +)\{/) && !$prevp) {
873*6236dae4SAndroid Build Coastguard Worker            checkwarn("BRACEPOS",
874*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol, "badly placed open brace");
875*6236dae4SAndroid Build Coastguard Worker        }
876*6236dae4SAndroid Build Coastguard Worker
877*6236dae4SAndroid Build Coastguard Worker        # if the previous line starts with if/while/for AND ends with an open
878*6236dae4SAndroid Build Coastguard Worker        # brace, or an else statement, check that this line is indented $indent
879*6236dae4SAndroid Build Coastguard Worker        # more steps, if not a cpp line
880*6236dae4SAndroid Build Coastguard Worker        if(!$prevp && ($prevl =~ /^( *)((if|while|for)\(.*\{|else)\z/)) {
881*6236dae4SAndroid Build Coastguard Worker            my $first = length($1);
882*6236dae4SAndroid Build Coastguard Worker            # this line has some character besides spaces
883*6236dae4SAndroid Build Coastguard Worker            if($l =~ /^( *)[^ ]/) {
884*6236dae4SAndroid Build Coastguard Worker                my $second = length($1);
885*6236dae4SAndroid Build Coastguard Worker                my $expect = $first+$indent;
886*6236dae4SAndroid Build Coastguard Worker                if($expect != $second) {
887*6236dae4SAndroid Build Coastguard Worker                    my $diff = $second - $first;
888*6236dae4SAndroid Build Coastguard Worker                    checkwarn("INDENTATION", $line, length($1), $file, $ol,
889*6236dae4SAndroid Build Coastguard Worker                              "not indented $indent steps (uses $diff)");
890*6236dae4SAndroid Build Coastguard Worker
891*6236dae4SAndroid Build Coastguard Worker                }
892*6236dae4SAndroid Build Coastguard Worker            }
893*6236dae4SAndroid Build Coastguard Worker        }
894*6236dae4SAndroid Build Coastguard Worker
895*6236dae4SAndroid Build Coastguard Worker        # if the previous line starts with if/while/for AND ends with a closed
896*6236dae4SAndroid Build Coastguard Worker        # parenthesis and there's an equal number of open and closed
897*6236dae4SAndroid Build Coastguard Worker        # parentheses, check that this line is indented $indent more steps, if
898*6236dae4SAndroid Build Coastguard Worker        # not a cpp line
899*6236dae4SAndroid Build Coastguard Worker        elsif(!$prevp && ($prevl =~ /^( *)(if|while|for)(\(.*\))\z/)) {
900*6236dae4SAndroid Build Coastguard Worker            my $first = length($1);
901*6236dae4SAndroid Build Coastguard Worker            my $op = $3;
902*6236dae4SAndroid Build Coastguard Worker            my $cl = $3;
903*6236dae4SAndroid Build Coastguard Worker
904*6236dae4SAndroid Build Coastguard Worker            $op =~ s/[^(]//g;
905*6236dae4SAndroid Build Coastguard Worker            $cl =~ s/[^)]//g;
906*6236dae4SAndroid Build Coastguard Worker
907*6236dae4SAndroid Build Coastguard Worker            if(length($op) == length($cl)) {
908*6236dae4SAndroid Build Coastguard Worker                # this line has some character besides spaces
909*6236dae4SAndroid Build Coastguard Worker                if($l =~ /^( *)[^ ]/) {
910*6236dae4SAndroid Build Coastguard Worker                    my $second = length($1);
911*6236dae4SAndroid Build Coastguard Worker                    my $expect = $first+$indent;
912*6236dae4SAndroid Build Coastguard Worker                    if($expect != $second) {
913*6236dae4SAndroid Build Coastguard Worker                        my $diff = $second - $first;
914*6236dae4SAndroid Build Coastguard Worker                        checkwarn("INDENTATION", $line, length($1), $file, $ol,
915*6236dae4SAndroid Build Coastguard Worker                                  "not indented $indent steps (uses $diff)");
916*6236dae4SAndroid Build Coastguard Worker                    }
917*6236dae4SAndroid Build Coastguard Worker                }
918*6236dae4SAndroid Build Coastguard Worker            }
919*6236dae4SAndroid Build Coastguard Worker        }
920*6236dae4SAndroid Build Coastguard Worker
921*6236dae4SAndroid Build Coastguard Worker        # check for 'char * name'
922*6236dae4SAndroid Build Coastguard Worker        if(($l =~ /(^.*(char|int|long|void|CURL|CURLM|CURLMsg|[cC]url_[A-Za-z_]+|struct [a-zA-Z_]+) *(\*+)) (\w+)/) && ($4 !~ /^(const|volatile)$/)) {
923*6236dae4SAndroid Build Coastguard Worker            checkwarn("ASTERISKSPACE",
924*6236dae4SAndroid Build Coastguard Worker                      $line, length($1), $file, $ol,
925*6236dae4SAndroid Build Coastguard Worker                      "space after declarative asterisk");
926*6236dae4SAndroid Build Coastguard Worker        }
927*6236dae4SAndroid Build Coastguard Worker        # check for 'char*'
928*6236dae4SAndroid Build Coastguard Worker        if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) {
929*6236dae4SAndroid Build Coastguard Worker            checkwarn("ASTERISKNOSPACE",
930*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)-1, $file, $ol,
931*6236dae4SAndroid Build Coastguard Worker                      "no space before asterisk");
932*6236dae4SAndroid Build Coastguard Worker        }
933*6236dae4SAndroid Build Coastguard Worker
934*6236dae4SAndroid Build Coastguard Worker        # check for 'void func() {', but avoid false positives by requiring
935*6236dae4SAndroid Build Coastguard Worker        # both an open and closed parentheses before the open brace
936*6236dae4SAndroid Build Coastguard Worker        if($l =~ /^((\w).*)\{\z/) {
937*6236dae4SAndroid Build Coastguard Worker            my $k = $1;
938*6236dae4SAndroid Build Coastguard Worker            $k =~ s/const *//;
939*6236dae4SAndroid Build Coastguard Worker            $k =~ s/static *//;
940*6236dae4SAndroid Build Coastguard Worker            if($k =~ /\(.*\)/) {
941*6236dae4SAndroid Build Coastguard Worker                checkwarn("BRACEPOS",
942*6236dae4SAndroid Build Coastguard Worker                          $line, length($l)-1, $file, $ol,
943*6236dae4SAndroid Build Coastguard Worker                          "wrongly placed open brace");
944*6236dae4SAndroid Build Coastguard Worker            }
945*6236dae4SAndroid Build Coastguard Worker        }
946*6236dae4SAndroid Build Coastguard Worker
947*6236dae4SAndroid Build Coastguard Worker        # check for equals sign without spaces next to it
948*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /(.*)\=[a-z0-9]/i) {
949*6236dae4SAndroid Build Coastguard Worker            checkwarn("EQUALSNOSPACE",
950*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
951*6236dae4SAndroid Build Coastguard Worker                      "no space after equals sign");
952*6236dae4SAndroid Build Coastguard Worker        }
953*6236dae4SAndroid Build Coastguard Worker        # check for equals sign without spaces before it
954*6236dae4SAndroid Build Coastguard Worker        elsif($nostr =~ /(.*)[a-z0-9]\=/i) {
955*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACEEQUALS",
956*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
957*6236dae4SAndroid Build Coastguard Worker                      "no space before equals sign");
958*6236dae4SAndroid Build Coastguard Worker        }
959*6236dae4SAndroid Build Coastguard Worker
960*6236dae4SAndroid Build Coastguard Worker        # check for plus signs without spaces next to it
961*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /(.*)[^+]\+[a-z0-9]/i) {
962*6236dae4SAndroid Build Coastguard Worker            checkwarn("PLUSNOSPACE",
963*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
964*6236dae4SAndroid Build Coastguard Worker                      "no space after plus sign");
965*6236dae4SAndroid Build Coastguard Worker        }
966*6236dae4SAndroid Build Coastguard Worker        # check for plus sign without spaces before it
967*6236dae4SAndroid Build Coastguard Worker        elsif($nostr =~ /(.*)[a-z0-9]\+[^+]/i) {
968*6236dae4SAndroid Build Coastguard Worker            checkwarn("NOSPACEPLUS",
969*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
970*6236dae4SAndroid Build Coastguard Worker                      "no space before plus sign");
971*6236dae4SAndroid Build Coastguard Worker        }
972*6236dae4SAndroid Build Coastguard Worker
973*6236dae4SAndroid Build Coastguard Worker        # check for semicolons without space next to it
974*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /(.*)\;[a-z0-9]/i) {
975*6236dae4SAndroid Build Coastguard Worker            checkwarn("SEMINOSPACE",
976*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
977*6236dae4SAndroid Build Coastguard Worker                      "no space after semicolon");
978*6236dae4SAndroid Build Coastguard Worker        }
979*6236dae4SAndroid Build Coastguard Worker
980*6236dae4SAndroid Build Coastguard Worker        # typedef struct ... {
981*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /^(.*)typedef struct.*{/) {
982*6236dae4SAndroid Build Coastguard Worker            checkwarn("TYPEDEFSTRUCT",
983*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
984*6236dae4SAndroid Build Coastguard Worker                      "typedef'ed struct");
985*6236dae4SAndroid Build Coastguard Worker        }
986*6236dae4SAndroid Build Coastguard Worker
987*6236dae4SAndroid Build Coastguard Worker        if($nostr =~ /(.*)! +(\w|\()/) {
988*6236dae4SAndroid Build Coastguard Worker            checkwarn("EXCLAMATIONSPACE",
989*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
990*6236dae4SAndroid Build Coastguard Worker                      "space after exclamation mark");
991*6236dae4SAndroid Build Coastguard Worker        }
992*6236dae4SAndroid Build Coastguard Worker
993*6236dae4SAndroid Build Coastguard Worker        # check for more than one consecutive space before open brace or
994*6236dae4SAndroid Build Coastguard Worker        # question mark. Skip lines containing strings since they make it hard
995*6236dae4SAndroid Build Coastguard Worker        # due to artificially getting multiple spaces
996*6236dae4SAndroid Build Coastguard Worker        if(($l eq $nostr) &&
997*6236dae4SAndroid Build Coastguard Worker           $nostr =~ /^(.*(\S)) + [{?]/i) {
998*6236dae4SAndroid Build Coastguard Worker            checkwarn("MULTISPACE",
999*6236dae4SAndroid Build Coastguard Worker                      $line, length($1)+1, $file, $ol,
1000*6236dae4SAndroid Build Coastguard Worker                      "multiple spaces");
1001*6236dae4SAndroid Build Coastguard Worker        }
1002*6236dae4SAndroid Build Coastguard Worker      preproc:
1003*6236dae4SAndroid Build Coastguard Worker        if($prep) {
1004*6236dae4SAndroid Build Coastguard Worker          # scan for use of banned symbols on a preprocessor line
1005*6236dae4SAndroid Build Coastguard Worker          if($l =~ /^(^|.*\W)
1006*6236dae4SAndroid Build Coastguard Worker                     (WIN32)
1007*6236dae4SAndroid Build Coastguard Worker                     (\W|$)
1008*6236dae4SAndroid Build Coastguard Worker                   /x) {
1009*6236dae4SAndroid Build Coastguard Worker              checkwarn("BANNEDPREPROC",
1010*6236dae4SAndroid Build Coastguard Worker                        $line, length($1), $file, $ol,
1011*6236dae4SAndroid Build Coastguard Worker                        "use of $2 is banned from preprocessor lines" .
1012*6236dae4SAndroid Build Coastguard Worker                        (($2 eq "WIN32") ? ", use _WIN32 instead" : ""));
1013*6236dae4SAndroid Build Coastguard Worker          }
1014*6236dae4SAndroid Build Coastguard Worker        }
1015*6236dae4SAndroid Build Coastguard Worker        $line++;
1016*6236dae4SAndroid Build Coastguard Worker        $prevp = $prep;
1017*6236dae4SAndroid Build Coastguard Worker        $prevl = $ol if(!$prep);
1018*6236dae4SAndroid Build Coastguard Worker        $prevpl = $ol if($prep);
1019*6236dae4SAndroid Build Coastguard Worker    }
1020*6236dae4SAndroid Build Coastguard Worker
1021*6236dae4SAndroid Build Coastguard Worker    if(!scalar(@copyright)) {
1022*6236dae4SAndroid Build Coastguard Worker        checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1);
1023*6236dae4SAndroid Build Coastguard Worker    }
1024*6236dae4SAndroid Build Coastguard Worker
1025*6236dae4SAndroid Build Coastguard Worker    # COPYRIGHTYEAR is an extended warning so we must first see if it has been
1026*6236dae4SAndroid Build Coastguard Worker    # enabled in .checksrc
1027*6236dae4SAndroid Build Coastguard Worker    if(defined($warnings{"COPYRIGHTYEAR"})) {
1028*6236dae4SAndroid Build Coastguard Worker        # The check for updated copyrightyear is overly complicated in order to
1029*6236dae4SAndroid Build Coastguard Worker        # not punish current hacking for past sins. The copyright years are
1030*6236dae4SAndroid Build Coastguard Worker        # right now a bit behind, so enforcing copyright year checking on all
1031*6236dae4SAndroid Build Coastguard Worker        # files would cause hundreds of errors. Instead we only look at files
1032*6236dae4SAndroid Build Coastguard Worker        # which are tracked in the Git repo and edited in the workdir, or
1033*6236dae4SAndroid Build Coastguard Worker        # committed locally on the branch without being in upstream master.
1034*6236dae4SAndroid Build Coastguard Worker        #
1035*6236dae4SAndroid Build Coastguard Worker        # The simple and naive test is to simply check for the current year,
1036*6236dae4SAndroid Build Coastguard Worker        # but updating the year even without an edit is against project policy
1037*6236dae4SAndroid Build Coastguard Worker        # (and it would fail every file on January 1st).
1038*6236dae4SAndroid Build Coastguard Worker        #
1039*6236dae4SAndroid Build Coastguard Worker        # A rather more interesting, and correct, check would be to not test
1040*6236dae4SAndroid Build Coastguard Worker        # only locally committed files but inspect all files wrt the year of
1041*6236dae4SAndroid Build Coastguard Worker        # their last commit. Removing the `git rev-list origin/master..HEAD`
1042*6236dae4SAndroid Build Coastguard Worker        # condition below will enforce copyright year checks against the year
1043*6236dae4SAndroid Build Coastguard Worker        # the file was last committed (and thus edited to some degree).
1044*6236dae4SAndroid Build Coastguard Worker        my $commityear = undef;
1045*6236dae4SAndroid Build Coastguard Worker        @copyright = sort {$$b{year} cmp $$a{year}} @copyright;
1046*6236dae4SAndroid Build Coastguard Worker
1047*6236dae4SAndroid Build Coastguard Worker        # if the file is modified, assume commit year this year
1048*6236dae4SAndroid Build Coastguard Worker        if(`git status -s -- "$file"` =~ /^ [MARCU]/) {
1049*6236dae4SAndroid Build Coastguard Worker            $commityear = (localtime(time))[5] + 1900;
1050*6236dae4SAndroid Build Coastguard Worker        }
1051*6236dae4SAndroid Build Coastguard Worker        else {
1052*6236dae4SAndroid Build Coastguard Worker            # min-parents=1 to ignore wrong initial commit in truncated repos
1053*6236dae4SAndroid Build Coastguard Worker            my $grl = `git rev-list --max-count=1 --min-parents=1 --timestamp HEAD -- "$file"`;
1054*6236dae4SAndroid Build Coastguard Worker            if($grl) {
1055*6236dae4SAndroid Build Coastguard Worker                chomp $grl;
1056*6236dae4SAndroid Build Coastguard Worker                $commityear = (localtime((split(/ /, $grl))[0]))[5] + 1900;
1057*6236dae4SAndroid Build Coastguard Worker            }
1058*6236dae4SAndroid Build Coastguard Worker        }
1059*6236dae4SAndroid Build Coastguard Worker
1060*6236dae4SAndroid Build Coastguard Worker        if(defined($commityear) && scalar(@copyright) &&
1061*6236dae4SAndroid Build Coastguard Worker           $copyright[0]{year} != $commityear) {
1062*6236dae4SAndroid Build Coastguard Worker            checkwarn("COPYRIGHTYEAR", $copyright[0]{line}, $copyright[0]{col},
1063*6236dae4SAndroid Build Coastguard Worker                      $file, $copyright[0]{code},
1064*6236dae4SAndroid Build Coastguard Worker                      "Copyright year out of date, should be $commityear, " .
1065*6236dae4SAndroid Build Coastguard Worker                      "is $copyright[0]{year}", 1);
1066*6236dae4SAndroid Build Coastguard Worker        }
1067*6236dae4SAndroid Build Coastguard Worker    }
1068*6236dae4SAndroid Build Coastguard Worker
1069*6236dae4SAndroid Build Coastguard Worker    if($incomment) {
1070*6236dae4SAndroid Build Coastguard Worker        checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1);
1071*6236dae4SAndroid Build Coastguard Worker    }
1072*6236dae4SAndroid Build Coastguard Worker
1073*6236dae4SAndroid Build Coastguard Worker    checksrc_endoffile($file);
1074*6236dae4SAndroid Build Coastguard Worker
1075*6236dae4SAndroid Build Coastguard Worker    close($R);
1076*6236dae4SAndroid Build Coastguard Worker
1077*6236dae4SAndroid Build Coastguard Worker}
1078*6236dae4SAndroid Build Coastguard Worker
1079*6236dae4SAndroid Build Coastguard Worker
1080*6236dae4SAndroid Build Coastguard Workerif($errors || $warnings || $verbose) {
1081*6236dae4SAndroid Build Coastguard Worker    printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
1082*6236dae4SAndroid Build Coastguard Worker    if($suppressed) {
1083*6236dae4SAndroid Build Coastguard Worker        printf "checksrc: %d errors and %d warnings suppressed\n",
1084*6236dae4SAndroid Build Coastguard Worker        $serrors,
1085*6236dae4SAndroid Build Coastguard Worker        $swarnings;
1086*6236dae4SAndroid Build Coastguard Worker    }
1087*6236dae4SAndroid Build Coastguard Worker    exit 5; # return failure
1088*6236dae4SAndroid Build Coastguard Worker}
1089