blob: b8eb57f38c74ae2feae98f9021d2c408ab579bbb [file] [log] [blame]
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001#!/usr/bin/env perl
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02002# SPDX-License-Identifier: GPL-2.0
3#
Joe Hershberger05622192011-10-18 10:06:59 +00004# (c) 2001, Dave Jones. (the file handling bit)
5# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
6# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
7# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02008# (c) 2010-2018 Joe Perches <joe@perches.com>
Joe Hershberger05622192011-10-18 10:06:59 +00009
10use strict;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020011use warnings;
Tom Rini6b9709d2014-02-27 08:27:28 -050012use POSIX;
Dan Murphyc10e0f52017-01-31 14:15:53 -060013use File::Basename;
14use Cwd 'abs_path';
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020015use Term::ANSIColor qw(:constants);
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +020016use Encode qw(decode encode);
Joe Hershberger05622192011-10-18 10:06:59 +000017
18my $P = $0;
Dan Murphyc10e0f52017-01-31 14:15:53 -060019my $D = dirname(abs_path($P));
Joe Hershberger05622192011-10-18 10:06:59 +000020
21my $V = '0.32';
22
23use Getopt::Long qw(:config no_auto_abbrev);
24
25my $quiet = 0;
Tom Rinie199fb32021-08-03 08:31:56 -040026my $verbose = 0;
27my %verbose_messages = ();
28my %verbose_emitted = ();
Joe Hershberger05622192011-10-18 10:06:59 +000029my $tree = 1;
30my $chk_signoff = 1;
31my $chk_patch = 1;
32my $tst_only;
33my $emacs = 0;
34my $terse = 0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020035my $showfile = 0;
Joe Hershberger05622192011-10-18 10:06:59 +000036my $file = 0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020037my $git = 0;
38my %git_commits = ();
Joe Hershberger05622192011-10-18 10:06:59 +000039my $check = 0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020040my $check_orig = 0;
Joe Hershberger05622192011-10-18 10:06:59 +000041my $summary = 1;
42my $mailback = 0;
43my $summary_file = 0;
44my $show_types = 0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020045my $list_types = 0;
Tom Rini6b9709d2014-02-27 08:27:28 -050046my $fix = 0;
47my $fix_inplace = 0;
Joe Hershberger05622192011-10-18 10:06:59 +000048my $root;
Tom Rinie199fb32021-08-03 08:31:56 -040049my $gitroot = $ENV{'GIT_DIR'};
50$gitroot = ".git" if !defined($gitroot);
Joe Hershberger05622192011-10-18 10:06:59 +000051my %debug;
Tom Rini6b9709d2014-02-27 08:27:28 -050052my %camelcase = ();
53my %use_type = ();
54my @use = ();
Joe Hershberger05622192011-10-18 10:06:59 +000055my %ignore_type = ();
56my @ignore = ();
57my $help = 0;
58my $configuration_file = ".checkpatch.conf";
Simon Glass048a6482020-05-22 16:32:35 -060059my $max_line_length = 100;
Tom Rini6b9709d2014-02-27 08:27:28 -050060my $ignore_perl_version = 0;
61my $minimum_perl_version = 5.10.0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020062my $min_conf_desc_length = 4;
Dan Murphyc10e0f52017-01-31 14:15:53 -060063my $spelling_file = "$D/spelling.txt";
64my $codespell = 0;
65my $codespellfile = "/usr/share/codespell/dictionary.txt";
Simon Glass587254e2022-01-23 12:55:11 -070066my $user_codespellfile = "";
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020067my $conststructsfile = "$D/const_structs.checkpatch";
Simon Glassb77df592020-05-22 16:32:36 -060068my $u_boot = 0;
Tom Rinie199fb32021-08-03 08:31:56 -040069my $docsfile = "$D/../doc/develop/checkpatch.rst";
70my $typedefsfile;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020071my $color = "auto";
Tom Rinic57383b2020-06-16 10:29:46 -040072my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE
73# git output parsing needs US English output, so first set backtick child process LANGUAGE
74my $git_command ='export LANGUAGE=en_US.UTF-8; git';
75my $tabsize = 8;
Tom Rinie199fb32021-08-03 08:31:56 -040076my ${CONFIG_} = "CONFIG_";
Joe Hershberger05622192011-10-18 10:06:59 +000077
78sub help {
79 my ($exitcode) = @_;
80
81 print << "EOM";
82Usage: $P [OPTION]... [FILE]...
83Version: $V
84
85Options:
86 -q, --quiet quiet
Tom Rinie199fb32021-08-03 08:31:56 -040087 -v, --verbose verbose mode
Joe Hershberger05622192011-10-18 10:06:59 +000088 --no-tree run without a kernel tree
89 --no-signoff do not check for 'Signed-off-by' line
90 --patch treat FILE as patchfile (default)
91 --emacs emacs compile window format
92 --terse one line per report
Heinrich Schuchardt6305db92017-09-12 09:57:45 +020093 --showfile emit diffed file position, not input file position
94 -g, --git treat FILE as a single commit or git revision range
95 single git commit with:
96 <rev>
97 <rev>^
98 <rev>~n
99 multiple git commits with:
100 <rev1>..<rev2>
101 <rev1>...<rev2>
102 <rev>-<count>
103 git merges are ignored
Joe Hershberger05622192011-10-18 10:06:59 +0000104 -f, --file treat FILE as regular source file
105 --subjective, --strict enable more subjective tests
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200106 --list-types list the possible message types
Tom Rini6b9709d2014-02-27 08:27:28 -0500107 --types TYPE(,TYPE2...) show only these comma separated message types
Joe Hershberger05622192011-10-18 10:06:59 +0000108 --ignore TYPE(,TYPE2...) ignore various comma separated message types
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200109 --show-types show the specific message type in the output
Simon Glass048a6482020-05-22 16:32:35 -0600110 --max-line-length=n set the maximum line length, (default $max_line_length)
111 if exceeded, warn on patches
112 requires --strict for use with --file
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200113 --min-conf-desc-length=n set the min description length, if shorter, warn
Tom Rinic57383b2020-06-16 10:29:46 -0400114 --tab-size=n set the number of spaces for tab (default $tabsize)
Joe Hershberger05622192011-10-18 10:06:59 +0000115 --root=PATH PATH to the kernel tree root
116 --no-summary suppress the per-file summary
117 --mailback only produce a report in case of warnings/errors
118 --summary-file include the filename in summary
119 --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of
120 'values', 'possible', 'type', and 'attr' (default
121 is all off)
122 --test-only=WORD report only warnings/errors containing WORD
123 literally
Tom Rini6b9709d2014-02-27 08:27:28 -0500124 --fix EXPERIMENTAL - may create horrible results
125 If correctable single-line errors exist, create
126 "<inputfile>.EXPERIMENTAL-checkpatch-fixes"
127 with potential errors corrected to the preferred
128 checkpatch style
129 --fix-inplace EXPERIMENTAL - may create horrible results
130 Is the same as --fix, but overwrites the input
131 file. It's your fault if there's no backup or git
132 --ignore-perl-version override checking of perl version. expect
133 runtime errors.
Dan Murphyc10e0f52017-01-31 14:15:53 -0600134 --codespell Use the codespell dictionary for spelling/typos
Simon Glass587254e2022-01-23 12:55:11 -0700135 (default:$codespellfile)
Dan Murphyc10e0f52017-01-31 14:15:53 -0600136 --codespellfile Use this codespell dictionary
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200137 --typedefsfile Read additional types from this file
138 --color[=WHEN] Use colors 'always', 'never', or only when output
139 is a terminal ('auto'). Default is 'auto'.
Simon Glassb77df592020-05-22 16:32:36 -0600140 --u-boot Run additional checks for U-Boot
Tom Rinie199fb32021-08-03 08:31:56 -0400141 --kconfig-prefix=WORD use WORD as a prefix for Kconfig symbols (default
142 ${CONFIG_})
Joe Hershberger05622192011-10-18 10:06:59 +0000143 -h, --help, --version display this help and exit
144
145When FILE is - read standard input.
146EOM
147
148 exit($exitcode);
149}
150
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200151sub uniq {
152 my %seen;
153 return grep { !$seen{$_}++ } @_;
154}
155
156sub list_types {
157 my ($exitcode) = @_;
158
159 my $count = 0;
160
161 local $/ = undef;
162
163 open(my $script, '<', abs_path($P)) or
164 die "$P: Can't read '$P' $!\n";
165
166 my $text = <$script>;
167 close($script);
168
Tom Rinie199fb32021-08-03 08:31:56 -0400169 my %types = ();
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +0200170 # Also catch when type or level is passed through a variable
Tom Rinie199fb32021-08-03 08:31:56 -0400171 while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
172 if (defined($1)) {
173 if (exists($types{$2})) {
174 $types{$2} .= ",$1" if ($types{$2} ne $1);
175 } else {
176 $types{$2} = $1;
177 }
178 } else {
179 $types{$2} = "UNDETERMINED";
180 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200181 }
Tom Rinie199fb32021-08-03 08:31:56 -0400182
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200183 print("#\tMessage type\n\n");
Tom Rinie199fb32021-08-03 08:31:56 -0400184 if ($color) {
185 print(" ( Color coding: ");
186 print(RED . "ERROR" . RESET);
187 print(" | ");
188 print(YELLOW . "WARNING" . RESET);
189 print(" | ");
190 print(GREEN . "CHECK" . RESET);
191 print(" | ");
192 print("Multiple levels / Undetermined");
193 print(" )\n\n");
194 }
195
196 foreach my $type (sort keys %types) {
197 my $orig_type = $type;
198 if ($color) {
199 my $level = $types{$type};
200 if ($level eq "ERROR") {
201 $type = RED . $type . RESET;
202 } elsif ($level eq "WARN") {
203 $type = YELLOW . $type . RESET;
204 } elsif ($level eq "CHK") {
205 $type = GREEN . $type . RESET;
206 }
207 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200208 print(++$count . "\t" . $type . "\n");
Tom Rinie199fb32021-08-03 08:31:56 -0400209 if ($verbose && exists($verbose_messages{$orig_type})) {
210 my $message = $verbose_messages{$orig_type};
211 $message =~ s/\n/\n\t/g;
212 print("\t" . $message . "\n\n");
213 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200214 }
215
216 exit($exitcode);
217}
218
Joe Hershberger05622192011-10-18 10:06:59 +0000219my $conf = which_conf($configuration_file);
220if (-f $conf) {
221 my @conf_args;
222 open(my $conffile, '<', "$conf")
223 or warn "$P: Can't find a readable $configuration_file file $!\n";
224
225 while (<$conffile>) {
226 my $line = $_;
227
228 $line =~ s/\s*\n?$//g;
229 $line =~ s/^\s*//g;
230 $line =~ s/\s+/ /g;
231
232 next if ($line =~ m/^\s*#/);
233 next if ($line =~ m/^\s*$/);
234
235 my @words = split(" ", $line);
236 foreach my $word (@words) {
237 last if ($word =~ m/^#/);
238 push (@conf_args, $word);
239 }
240 }
241 close($conffile);
242 unshift(@ARGV, @conf_args) if @conf_args;
243}
244
Tom Rinie199fb32021-08-03 08:31:56 -0400245sub load_docs {
246 open(my $docs, '<', "$docsfile")
247 or warn "$P: Can't read the documentation file $docsfile $!\n";
248
249 my $type = '';
250 my $desc = '';
251 my $in_desc = 0;
252
253 while (<$docs>) {
254 chomp;
255 my $line = $_;
256 $line =~ s/\s+$//;
257
258 if ($line =~ /^\s*\*\*(.+)\*\*$/) {
259 if ($desc ne '') {
260 $verbose_messages{$type} = trim($desc);
261 }
262 $type = $1;
263 $desc = '';
264 $in_desc = 1;
265 } elsif ($in_desc) {
266 if ($line =~ /^(?:\s{4,}|$)/) {
267 $line =~ s/^\s{4}//;
268 $desc .= $line;
269 $desc .= "\n";
270 } else {
271 $verbose_messages{$type} = trim($desc);
272 $type = '';
273 $desc = '';
274 $in_desc = 0;
275 }
276 }
277 }
278
279 if ($desc ne '') {
280 $verbose_messages{$type} = trim($desc);
281 }
282 close($docs);
283}
284
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200285# Perl's Getopt::Long allows options to take optional arguments after a space.
286# Prevent --color by itself from consuming other arguments
287foreach (@ARGV) {
288 if ($_ eq "--color" || $_ eq "-color") {
289 $_ = "--color=$color";
290 }
291}
292
Joe Hershberger05622192011-10-18 10:06:59 +0000293GetOptions(
294 'q|quiet+' => \$quiet,
Tom Rinie199fb32021-08-03 08:31:56 -0400295 'v|verbose!' => \$verbose,
Joe Hershberger05622192011-10-18 10:06:59 +0000296 'tree!' => \$tree,
297 'signoff!' => \$chk_signoff,
298 'patch!' => \$chk_patch,
299 'emacs!' => \$emacs,
300 'terse!' => \$terse,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200301 'showfile!' => \$showfile,
Joe Hershberger05622192011-10-18 10:06:59 +0000302 'f|file!' => \$file,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200303 'g|git!' => \$git,
Joe Hershberger05622192011-10-18 10:06:59 +0000304 'subjective!' => \$check,
305 'strict!' => \$check,
306 'ignore=s' => \@ignore,
Tom Rini6b9709d2014-02-27 08:27:28 -0500307 'types=s' => \@use,
Joe Hershberger05622192011-10-18 10:06:59 +0000308 'show-types!' => \$show_types,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200309 'list-types!' => \$list_types,
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000310 'max-line-length=i' => \$max_line_length,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200311 'min-conf-desc-length=i' => \$min_conf_desc_length,
Tom Rinic57383b2020-06-16 10:29:46 -0400312 'tab-size=i' => \$tabsize,
Joe Hershberger05622192011-10-18 10:06:59 +0000313 'root=s' => \$root,
314 'summary!' => \$summary,
315 'mailback!' => \$mailback,
316 'summary-file!' => \$summary_file,
Tom Rini6b9709d2014-02-27 08:27:28 -0500317 'fix!' => \$fix,
318 'fix-inplace!' => \$fix_inplace,
319 'ignore-perl-version!' => \$ignore_perl_version,
Joe Hershberger05622192011-10-18 10:06:59 +0000320 'debug=s' => \%debug,
321 'test-only=s' => \$tst_only,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200322 'codespell!' => \$codespell,
Simon Glass587254e2022-01-23 12:55:11 -0700323 'codespellfile=s' => \$user_codespellfile,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200324 'typedefsfile=s' => \$typedefsfile,
Simon Glassb77df592020-05-22 16:32:36 -0600325 'u-boot' => \$u_boot,
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200326 'color=s' => \$color,
327 'no-color' => \$color, #keep old behaviors of -nocolor
328 'nocolor' => \$color, #keep old behaviors of -nocolor
Tom Rinie199fb32021-08-03 08:31:56 -0400329 'kconfig-prefix=s' => \${CONFIG_},
Joe Hershberger05622192011-10-18 10:06:59 +0000330 'h|help' => \$help,
331 'version' => \$help
Simon Glass587254e2022-01-23 12:55:11 -0700332) or $help = 2;
Joe Hershberger05622192011-10-18 10:06:59 +0000333
Simon Glass587254e2022-01-23 12:55:11 -0700334if ($user_codespellfile) {
335 # Use the user provided codespell file unconditionally
336 $codespellfile = $user_codespellfile;
337} elsif (!(-f $codespellfile)) {
338 # If /usr/share/codespell/dictionary.txt is not present, try to find it
339 # under codespell's install directory: <codespell_root>/data/dictionary.txt
340 if (($codespell || $help) && which("codespell") ne "" && which("python") ne "") {
341 my $python_codespell_dict = << "EOF";
342
343import os.path as op
344import codespell_lib
345codespell_dir = op.dirname(codespell_lib.__file__)
346codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt')
347print(codespell_file, end='')
348EOF
349
350 my $codespell_dict = `python -c "$python_codespell_dict" 2> /dev/null`;
351 $codespellfile = $codespell_dict if (-f $codespell_dict);
352 }
353}
354
355# $help is 1 if either -h, --help or --version is passed as option - exitcode: 0
356# $help is 2 if invalid option is passed - exitcode: 1
357help($help - 1) if ($help);
Joe Hershberger05622192011-10-18 10:06:59 +0000358
Tom Rinie199fb32021-08-03 08:31:56 -0400359die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
360die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
361
362if ($color =~ /^[01]$/) {
363 $color = !$color;
364} elsif ($color =~ /^always$/i) {
365 $color = 1;
366} elsif ($color =~ /^never$/i) {
367 $color = 0;
368} elsif ($color =~ /^auto$/i) {
369 $color = (-t STDOUT);
370} else {
371 die "$P: Invalid color mode: $color\n";
372}
373
374load_docs() if ($verbose);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200375list_types(0) if ($list_types);
376
Tom Rini6b9709d2014-02-27 08:27:28 -0500377$fix = 1 if ($fix_inplace);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200378$check_orig = $check;
Tom Rini6b9709d2014-02-27 08:27:28 -0500379
Joe Hershberger05622192011-10-18 10:06:59 +0000380my $exit = 0;
381
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +0200382my $perl_version_ok = 1;
Tom Rini6b9709d2014-02-27 08:27:28 -0500383if ($^V && $^V lt $minimum_perl_version) {
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +0200384 $perl_version_ok = 0;
Tom Rini6b9709d2014-02-27 08:27:28 -0500385 printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +0200386 exit(1) if (!$ignore_perl_version);
Tom Rini6b9709d2014-02-27 08:27:28 -0500387}
388
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200389#if no filenames are given, push '-' to read patch from stdin
Joe Hershberger05622192011-10-18 10:06:59 +0000390if ($#ARGV < 0) {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200391 push(@ARGV, '-');
392}
393
Tom Rinic57383b2020-06-16 10:29:46 -0400394# skip TAB size 1 to avoid additional checks on $tabsize - 1
Tom Rinie199fb32021-08-03 08:31:56 -0400395die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2);
Tom Rinic57383b2020-06-16 10:29:46 -0400396
Tom Rini6b9709d2014-02-27 08:27:28 -0500397sub hash_save_array_words {
398 my ($hashRef, $arrayRef) = @_;
Joe Hershberger05622192011-10-18 10:06:59 +0000399
Tom Rini6b9709d2014-02-27 08:27:28 -0500400 my @array = split(/,/, join(',', @$arrayRef));
401 foreach my $word (@array) {
402 $word =~ s/\s*\n?$//g;
403 $word =~ s/^\s*//g;
404 $word =~ s/\s+/ /g;
405 $word =~ tr/[a-z]/[A-Z]/;
Joe Hershberger05622192011-10-18 10:06:59 +0000406
Tom Rini6b9709d2014-02-27 08:27:28 -0500407 next if ($word =~ m/^\s*#/);
408 next if ($word =~ m/^\s*$/);
409
410 $hashRef->{$word}++;
411 }
Joe Hershberger05622192011-10-18 10:06:59 +0000412}
413
Tom Rini6b9709d2014-02-27 08:27:28 -0500414sub hash_show_words {
415 my ($hashRef, $prefix) = @_;
416
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200417 if (keys %$hashRef) {
418 print "\nNOTE: $prefix message types:";
Tom Rini6b9709d2014-02-27 08:27:28 -0500419 foreach my $word (sort keys %$hashRef) {
420 print " $word";
421 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200422 print "\n";
Tom Rini6b9709d2014-02-27 08:27:28 -0500423 }
424}
425
426hash_save_array_words(\%ignore_type, \@ignore);
427hash_save_array_words(\%use_type, \@use);
428
Joe Hershberger05622192011-10-18 10:06:59 +0000429my $dbg_values = 0;
430my $dbg_possible = 0;
431my $dbg_type = 0;
432my $dbg_attr = 0;
433for my $key (keys %debug) {
434 ## no critic
435 eval "\${dbg_$key} = '$debug{$key}';";
436 die "$@" if ($@);
437}
438
439my $rpt_cleaners = 0;
440
441if ($terse) {
442 $emacs = 1;
443 $quiet++;
444}
445
446if ($tree) {
447 if (defined $root) {
448 if (!top_of_kernel_tree($root)) {
449 die "$P: $root: --root does not point at a valid tree\n";
450 }
451 } else {
452 if (top_of_kernel_tree('.')) {
453 $root = '.';
454 } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
455 top_of_kernel_tree($1)) {
456 $root = $1;
457 }
458 }
459
460 if (!defined $root) {
461 print "Must be run from the top-level dir. of a kernel tree\n";
462 exit(2);
463 }
464}
465
466my $emitted_corrupt = 0;
467
468our $Ident = qr{
469 [A-Za-z_][A-Za-z\d_]*
470 (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
471 }x;
472our $Storage = qr{extern|static|asmlinkage};
473our $Sparse = qr{
474 __user|
475 __kernel|
476 __force|
477 __iomem|
478 __must_check|
Joe Hershberger05622192011-10-18 10:06:59 +0000479 __kprobes|
480 __ref|
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +0200481 __refconst|
482 __refdata|
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200483 __rcu|
484 __private
Joe Hershberger05622192011-10-18 10:06:59 +0000485 }x;
Tom Rini6b9709d2014-02-27 08:27:28 -0500486our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)};
487our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)};
488our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)};
489our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)};
490our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit};
Joe Hershberger05622192011-10-18 10:06:59 +0000491
492# Notes to $Attribute:
493# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
494our $Attribute = qr{
495 const|
Tom Rinie199fb32021-08-03 08:31:56 -0400496 volatile|
Joe Hershberger05622192011-10-18 10:06:59 +0000497 __percpu|
498 __nocast|
499 __safe|
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200500 __bitwise|
Joe Hershberger05622192011-10-18 10:06:59 +0000501 __packed__|
502 __packed2__|
503 __naked|
504 __maybe_unused|
505 __always_unused|
506 __noreturn|
507 __used|
508 __cold|
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200509 __pure|
Joe Hershberger05622192011-10-18 10:06:59 +0000510 __noclone|
511 __deprecated|
512 __read_mostly|
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +0200513 __ro_after_init|
Joe Hershberger05622192011-10-18 10:06:59 +0000514 __kprobes|
Tom Rini6b9709d2014-02-27 08:27:28 -0500515 $InitAttribute|
Joe Hershberger05622192011-10-18 10:06:59 +0000516 ____cacheline_aligned|
517 ____cacheline_aligned_in_smp|
518 ____cacheline_internodealigned_in_smp|
Simon Glass587254e2022-01-23 12:55:11 -0700519 __weak|
520 __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\)
Joe Hershberger05622192011-10-18 10:06:59 +0000521 }x;
522our $Modifier;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200523our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__};
Joe Hershberger05622192011-10-18 10:06:59 +0000524our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
525our $Lval = qr{$Ident(?:$Member)*};
526
Tom Rini6b9709d2014-02-27 08:27:28 -0500527our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u};
528our $Binary = qr{(?i)0b[01]+$Int_type?};
529our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?};
530our $Int = qr{[0-9]+$Int_type?};
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200531our $Octal = qr{0[0-7]+$Int_type?};
Simon Glass587254e2022-01-23 12:55:11 -0700532our $String = qr{(?:\b[Lu])?"[X\t]*"};
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000533our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
534our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
535our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
536our $Float = qr{$Float_hex|$Float_dec|$Float_int};
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200537our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int};
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000538our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200539our $Compare = qr{<=|>=|==|!=|<|(?<!-)>};
Tom Rini6b9709d2014-02-27 08:27:28 -0500540our $Arithmetic = qr{\+|-|\*|\/|%};
Joe Hershberger05622192011-10-18 10:06:59 +0000541our $Operators = qr{
542 <=|>=|==|!=|
543 =>|->|<<|>>|<|>|!|~|
Tom Rini6b9709d2014-02-27 08:27:28 -0500544 &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
Joe Hershberger05622192011-10-18 10:06:59 +0000545 }x;
546
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200547our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x;
548
549our $BasicType;
Joe Hershberger05622192011-10-18 10:06:59 +0000550our $NonptrType;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200551our $NonptrTypeMisordered;
Tom Rini6b9709d2014-02-27 08:27:28 -0500552our $NonptrTypeWithAttr;
Joe Hershberger05622192011-10-18 10:06:59 +0000553our $Type;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200554our $TypeMisordered;
Joe Hershberger05622192011-10-18 10:06:59 +0000555our $Declare;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200556our $DeclareMisordered;
Joe Hershberger05622192011-10-18 10:06:59 +0000557
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000558our $NON_ASCII_UTF8 = qr{
559 [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
Joe Hershberger05622192011-10-18 10:06:59 +0000560 | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
561 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
562 | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
563 | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
564 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
565 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
566}x;
567
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000568our $UTF8 = qr{
569 [\x09\x0A\x0D\x20-\x7E] # ASCII
570 | $NON_ASCII_UTF8
571}x;
572
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200573our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t};
574our $typeOtherOSTypedefs = qr{(?x:
575 u_(?:char|short|int|long) | # bsd
576 u(?:nchar|short|int|long) # sysv
577)};
578our $typeKernelTypedefs = qr{(?x:
Joe Hershberger05622192011-10-18 10:06:59 +0000579 (?:__)?(?:u|s|be|le)(?:8|16|32|64)|
580 atomic_t
581)};
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200582our $typeTypedefs = qr{(?x:
583 $typeC99Typedefs\b|
584 $typeOtherOSTypedefs\b|
585 $typeKernelTypedefs\b
586)};
587
588our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
Joe Hershberger05622192011-10-18 10:06:59 +0000589
590our $logFunctions = qr{(?x:
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200591 printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
Tom Rini6b9709d2014-02-27 08:27:28 -0500592 (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +0200593 TP_printk|
Joe Hershberger05622192011-10-18 10:06:59 +0000594 WARN(?:_RATELIMIT|_ONCE|)|
595 panic|
James Byrne66b3ccc2019-11-21 14:32:46 +0000596 debug|
597 printf|
Tom Rini6b9709d2014-02-27 08:27:28 -0500598 MODULE_[A-Z_]+|
599 seq_vprintf|seq_printf|seq_puts
Joe Hershberger05622192011-10-18 10:06:59 +0000600)};
601
Tom Rinic57383b2020-06-16 10:29:46 -0400602our $allocFunctions = qr{(?x:
603 (?:(?:devm_)?
Tom Rinie199fb32021-08-03 08:31:56 -0400604 (?:kv|k|v)[czm]alloc(?:_array)?(?:_node)? |
Tom Rinic57383b2020-06-16 10:29:46 -0400605 kstrdup(?:_const)? |
606 kmemdup(?:_nul)?) |
607 (?:\w+)?alloc_skb(?:_ip_align)? |
608 # dev_alloc_skb/netdev_alloc_skb, et al
609 dma_alloc_coherent
610)};
611
Joe Hershberger05622192011-10-18 10:06:59 +0000612our $signature_tags = qr{(?xi:
613 Signed-off-by:|
Tom Rinic57383b2020-06-16 10:29:46 -0400614 Co-developed-by:|
Joe Hershberger05622192011-10-18 10:06:59 +0000615 Acked-by:|
616 Tested-by:|
617 Reviewed-by:|
618 Reported-by:|
Tom Rini6b9709d2014-02-27 08:27:28 -0500619 Suggested-by:|
Joe Hershberger05622192011-10-18 10:06:59 +0000620 To:|
621 Cc:
622)};
623
Tom Rinie199fb32021-08-03 08:31:56 -0400624our $tracing_logging_tags = qr{(?xi:
625 [=-]*> |
626 <[=-]* |
627 \[ |
628 \] |
629 start |
630 called |
631 entered |
632 entry |
633 enter |
634 in |
635 inside |
636 here |
637 begin |
638 exit |
639 end |
640 done |
641 leave |
642 completed |
643 out |
644 return |
645 [\.\!:\s]*
646)};
647
648sub edit_distance_min {
649 my (@arr) = @_;
650 my $len = scalar @arr;
651 if ((scalar @arr) < 1) {
652 # if underflow, return
653 return;
654 }
655 my $min = $arr[0];
656 for my $i (0 .. ($len-1)) {
657 if ($arr[$i] < $min) {
658 $min = $arr[$i];
659 }
660 }
661 return $min;
662}
663
664sub get_edit_distance {
665 my ($str1, $str2) = @_;
666 $str1 = lc($str1);
667 $str2 = lc($str2);
668 $str1 =~ s/-//g;
669 $str2 =~ s/-//g;
670 my $len1 = length($str1);
671 my $len2 = length($str2);
672 # two dimensional array storing minimum edit distance
673 my @distance;
674 for my $i (0 .. $len1) {
675 for my $j (0 .. $len2) {
676 if ($i == 0) {
677 $distance[$i][$j] = $j;
678 } elsif ($j == 0) {
679 $distance[$i][$j] = $i;
680 } elsif (substr($str1, $i-1, 1) eq substr($str2, $j-1, 1)) {
681 $distance[$i][$j] = $distance[$i - 1][$j - 1];
682 } else {
683 my $dist1 = $distance[$i][$j - 1]; #insert distance
684 my $dist2 = $distance[$i - 1][$j]; # remove
685 my $dist3 = $distance[$i - 1][$j - 1]; #replace
686 $distance[$i][$j] = 1 + edit_distance_min($dist1, $dist2, $dist3);
687 }
688 }
689 }
690 return $distance[$len1][$len2];
691}
692
693sub find_standard_signature {
694 my ($sign_off) = @_;
695 my @standard_signature_tags = (
696 'Signed-off-by:', 'Co-developed-by:', 'Acked-by:', 'Tested-by:',
697 'Reviewed-by:', 'Reported-by:', 'Suggested-by:'
698 );
699 foreach my $signature (@standard_signature_tags) {
700 return $signature if (get_edit_distance($sign_off, $signature) <= 2);
701 }
702
703 return "";
704}
705
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200706our @typeListMisordered = (
707 qr{char\s+(?:un)?signed},
708 qr{int\s+(?:(?:un)?signed\s+)?short\s},
709 qr{int\s+short(?:\s+(?:un)?signed)},
710 qr{short\s+int(?:\s+(?:un)?signed)},
711 qr{(?:un)?signed\s+int\s+short},
712 qr{short\s+(?:un)?signed},
713 qr{long\s+int\s+(?:un)?signed},
714 qr{int\s+long\s+(?:un)?signed},
715 qr{long\s+(?:un)?signed\s+int},
716 qr{int\s+(?:un)?signed\s+long},
717 qr{int\s+(?:un)?signed},
718 qr{int\s+long\s+long\s+(?:un)?signed},
719 qr{long\s+long\s+int\s+(?:un)?signed},
720 qr{long\s+long\s+(?:un)?signed\s+int},
721 qr{long\s+long\s+(?:un)?signed},
722 qr{long\s+(?:un)?signed},
723);
724
Joe Hershberger05622192011-10-18 10:06:59 +0000725our @typeList = (
726 qr{void},
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200727 qr{(?:(?:un)?signed\s+)?char},
728 qr{(?:(?:un)?signed\s+)?short\s+int},
729 qr{(?:(?:un)?signed\s+)?short},
730 qr{(?:(?:un)?signed\s+)?int},
731 qr{(?:(?:un)?signed\s+)?long\s+int},
732 qr{(?:(?:un)?signed\s+)?long\s+long\s+int},
733 qr{(?:(?:un)?signed\s+)?long\s+long},
734 qr{(?:(?:un)?signed\s+)?long},
735 qr{(?:un)?signed},
Joe Hershberger05622192011-10-18 10:06:59 +0000736 qr{float},
737 qr{double},
738 qr{bool},
739 qr{struct\s+$Ident},
740 qr{union\s+$Ident},
741 qr{enum\s+$Ident},
742 qr{${Ident}_t},
743 qr{${Ident}_handler},
744 qr{${Ident}_handler_fn},
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200745 @typeListMisordered,
Joe Hershberger05622192011-10-18 10:06:59 +0000746);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200747
748our $C90_int_types = qr{(?x:
749 long\s+long\s+int\s+(?:un)?signed|
750 long\s+long\s+(?:un)?signed\s+int|
751 long\s+long\s+(?:un)?signed|
752 (?:(?:un)?signed\s+)?long\s+long\s+int|
753 (?:(?:un)?signed\s+)?long\s+long|
754 int\s+long\s+long\s+(?:un)?signed|
755 int\s+(?:(?:un)?signed\s+)?long\s+long|
756
757 long\s+int\s+(?:un)?signed|
758 long\s+(?:un)?signed\s+int|
759 long\s+(?:un)?signed|
760 (?:(?:un)?signed\s+)?long\s+int|
761 (?:(?:un)?signed\s+)?long|
762 int\s+long\s+(?:un)?signed|
763 int\s+(?:(?:un)?signed\s+)?long|
764
765 int\s+(?:un)?signed|
766 (?:(?:un)?signed\s+)?int
767)};
768
769our @typeListFile = ();
Tom Rini6b9709d2014-02-27 08:27:28 -0500770our @typeListWithAttr = (
771 @typeList,
772 qr{struct\s+$InitAttribute\s+$Ident},
773 qr{union\s+$InitAttribute\s+$Ident},
774);
775
Joe Hershberger05622192011-10-18 10:06:59 +0000776our @modifierList = (
777 qr{fastcall},
778);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200779our @modifierListFile = ();
780
781our @mode_permission_funcs = (
782 ["module_param", 3],
783 ["module_param_(?:array|named|string)", 4],
784 ["module_param_array_named", 5],
785 ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2],
786 ["proc_create(?:_data|)", 2],
787 ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2],
788 ["IIO_DEV_ATTR_[A-Z_]+", 1],
789 ["SENSOR_(?:DEVICE_|)ATTR_2", 2],
790 ["SENSOR_TEMPLATE(?:_2|)", 3],
791 ["__ATTR", 2],
792);
793
Tom Rinie199fb32021-08-03 08:31:56 -0400794my $word_pattern = '\b[A-Z]?[a-z]{2,}\b';
795
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200796#Create a search pattern for all these functions to speed up a loop below
797our $mode_perms_search = "";
798foreach my $entry (@mode_permission_funcs) {
799 $mode_perms_search .= '|' if ($mode_perms_search ne "");
800 $mode_perms_search .= $entry->[0];
801}
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +0200802$mode_perms_search = "(?:${mode_perms_search})";
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200803
Tom Rinic57383b2020-06-16 10:29:46 -0400804our %deprecated_apis = (
805 "synchronize_rcu_bh" => "synchronize_rcu",
806 "synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited",
807 "call_rcu_bh" => "call_rcu",
808 "rcu_barrier_bh" => "rcu_barrier",
809 "synchronize_sched" => "synchronize_rcu",
810 "synchronize_sched_expedited" => "synchronize_rcu_expedited",
811 "call_rcu_sched" => "call_rcu",
812 "rcu_barrier_sched" => "rcu_barrier",
813 "get_state_synchronize_sched" => "get_state_synchronize_rcu",
814 "cond_synchronize_sched" => "cond_synchronize_rcu",
815);
816
817#Create a search pattern for all these strings to speed up a loop below
818our $deprecated_apis_search = "";
819foreach my $entry (keys %deprecated_apis) {
820 $deprecated_apis_search .= '|' if ($deprecated_apis_search ne "");
821 $deprecated_apis_search .= $entry;
822}
823$deprecated_apis_search = "(?:${deprecated_apis_search})";
824
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200825our $mode_perms_world_writable = qr{
826 S_IWUGO |
827 S_IWOTH |
828 S_IRWXUGO |
829 S_IALLUGO |
830 0[0-7][0-7][2367]
831}x;
832
833our %mode_permission_string_types = (
834 "S_IRWXU" => 0700,
835 "S_IRUSR" => 0400,
836 "S_IWUSR" => 0200,
837 "S_IXUSR" => 0100,
838 "S_IRWXG" => 0070,
839 "S_IRGRP" => 0040,
840 "S_IWGRP" => 0020,
841 "S_IXGRP" => 0010,
842 "S_IRWXO" => 0007,
843 "S_IROTH" => 0004,
844 "S_IWOTH" => 0002,
845 "S_IXOTH" => 0001,
846 "S_IRWXUGO" => 0777,
847 "S_IRUGO" => 0444,
848 "S_IWUGO" => 0222,
849 "S_IXUGO" => 0111,
850);
851
852#Create a search pattern for all these strings to speed up a loop below
853our $mode_perms_string_search = "";
854foreach my $entry (keys %mode_permission_string_types) {
855 $mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
856 $mode_perms_string_search .= $entry;
857}
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +0200858our $single_mode_perms_string_search = "(?:${mode_perms_string_search})";
859our $multi_mode_perms_string_search = qr{
860 ${single_mode_perms_string_search}
861 (?:\s*\|\s*${single_mode_perms_string_search})*
862}x;
863
864sub perms_to_octal {
865 my ($string) = @_;
866
867 return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/);
868
869 my $val = "";
870 my $oval = "";
871 my $to = 0;
872 my $curpos = 0;
873 my $lastpos = 0;
874 while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
875 $curpos = pos($string);
876 my $match = $2;
877 my $omatch = $1;
878 last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
879 $lastpos = $curpos;
880 $to |= $mode_permission_string_types{$match};
881 $val .= '\s*\|\s*' if ($val ne "");
882 $val .= $match;
883 $oval .= $omatch;
884 }
885 $oval =~ s/^\s*\|\s*//;
886 $oval =~ s/\s*\|\s*$//;
887 return sprintf("%04o", $to);
888}
Joe Hershberger05622192011-10-18 10:06:59 +0000889
890our $allowed_asm_includes = qr{(?x:
891 irq|
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200892 memory|
893 time|
894 reboot
Joe Hershberger05622192011-10-18 10:06:59 +0000895)};
896# memory.h: ARM has a custom one
897
Dan Murphyc10e0f52017-01-31 14:15:53 -0600898# Load common spelling mistakes and build regular expression list.
899my $misspellings;
900my %spelling_fix;
901
902if (open(my $spelling, '<', $spelling_file)) {
903 while (<$spelling>) {
904 my $line = $_;
905
906 $line =~ s/\s*\n?$//g;
907 $line =~ s/^\s*//g;
908
909 next if ($line =~ m/^\s*#/);
910 next if ($line =~ m/^\s*$/);
911
912 my ($suspect, $fix) = split(/\|\|/, $line);
913
914 $spelling_fix{$suspect} = $fix;
915 }
916 close($spelling);
917} else {
918 warn "No typos will be found - file '$spelling_file': $!\n";
919}
920
921if ($codespell) {
922 if (open(my $spelling, '<', $codespellfile)) {
923 while (<$spelling>) {
924 my $line = $_;
925
926 $line =~ s/\s*\n?$//g;
927 $line =~ s/^\s*//g;
928
929 next if ($line =~ m/^\s*#/);
930 next if ($line =~ m/^\s*$/);
931 next if ($line =~ m/, disabled/i);
932
933 $line =~ s/,.*$//;
934
935 my ($suspect, $fix) = split(/->/, $line);
936
937 $spelling_fix{$suspect} = $fix;
938 }
939 close($spelling);
940 } else {
941 warn "No codespell typos will be found - file '$codespellfile': $!\n";
942 }
943}
944
945$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix;
946
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200947sub read_words {
948 my ($wordsRef, $file) = @_;
949
950 if (open(my $words, '<', $file)) {
951 while (<$words>) {
952 my $line = $_;
953
954 $line =~ s/\s*\n?$//g;
955 $line =~ s/^\s*//g;
956
957 next if ($line =~ m/^\s*#/);
958 next if ($line =~ m/^\s*$/);
959 if ($line =~ /\s/) {
960 print("$file: '$line' invalid - ignored\n");
961 next;
962 }
963
Tom Rinie199fb32021-08-03 08:31:56 -0400964 $$wordsRef .= '|' if (defined $$wordsRef);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200965 $$wordsRef .= $line;
966 }
967 close($file);
968 return 1;
969 }
970
971 return 0;
972}
973
Tom Rinie199fb32021-08-03 08:31:56 -0400974my $const_structs;
975if (show_type("CONST_STRUCT")) {
976 read_words(\$const_structs, $conststructsfile)
977 or warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
978}
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200979
Tom Rinie199fb32021-08-03 08:31:56 -0400980if (defined($typedefsfile)) {
981 my $typeOtherTypedefs;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200982 read_words(\$typeOtherTypedefs, $typedefsfile)
983 or warn "No additional types will be considered - file '$typedefsfile': $!\n";
Tom Rinie199fb32021-08-03 08:31:56 -0400984 $typeTypedefs .= '|' . $typeOtherTypedefs if (defined $typeOtherTypedefs);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200985}
Dan Murphyc10e0f52017-01-31 14:15:53 -0600986
Joe Hershberger05622192011-10-18 10:06:59 +0000987sub build_types {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200988 my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)";
989 my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)";
990 my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)";
Tom Rini6b9709d2014-02-27 08:27:28 -0500991 my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)";
Joe Hershberger05622192011-10-18 10:06:59 +0000992 $Modifier = qr{(?:$Attribute|$Sparse|$mods)};
Heinrich Schuchardt6305db92017-09-12 09:57:45 +0200993 $BasicType = qr{
994 (?:$typeTypedefs\b)|
995 (?:${all}\b)
996 }x;
Joe Hershberger05622192011-10-18 10:06:59 +0000997 $NonptrType = qr{
998 (?:$Modifier\s+|const\s+)*
999 (?:
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00001000 (?:typeof|__typeof__)\s*\([^\)]*\)|
Joe Hershberger05622192011-10-18 10:06:59 +00001001 (?:$typeTypedefs\b)|
1002 (?:${all}\b)
1003 )
1004 (?:\s+$Modifier|\s+const)*
1005 }x;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001006 $NonptrTypeMisordered = qr{
1007 (?:$Modifier\s+|const\s+)*
1008 (?:
1009 (?:${Misordered}\b)
1010 )
1011 (?:\s+$Modifier|\s+const)*
1012 }x;
Tom Rini6b9709d2014-02-27 08:27:28 -05001013 $NonptrTypeWithAttr = qr{
1014 (?:$Modifier\s+|const\s+)*
1015 (?:
1016 (?:typeof|__typeof__)\s*\([^\)]*\)|
1017 (?:$typeTypedefs\b)|
1018 (?:${allWithAttr}\b)
1019 )
1020 (?:\s+$Modifier|\s+const)*
1021 }x;
Joe Hershberger05622192011-10-18 10:06:59 +00001022 $Type = qr{
1023 $NonptrType
Tom Rinic57383b2020-06-16 10:29:46 -04001024 (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4}
Joe Hershberger05622192011-10-18 10:06:59 +00001025 (?:\s+$Inline|\s+$Modifier)*
1026 }x;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001027 $TypeMisordered = qr{
1028 $NonptrTypeMisordered
Tom Rinic57383b2020-06-16 10:29:46 -04001029 (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4}
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001030 (?:\s+$Inline|\s+$Modifier)*
1031 }x;
1032 $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type};
1033 $DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered};
Joe Hershberger05622192011-10-18 10:06:59 +00001034}
1035build_types();
1036
Joe Hershberger05622192011-10-18 10:06:59 +00001037our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00001038
1039# Using $balanced_parens, $LvalOrFunc, or $FuncArg
1040# requires at least perl version v5.10.0
1041# Any use must be runtime checked with $^V
1042
1043our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001044our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*};
1045our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
1046
1047our $declaration_macros = qr{(?x:
1048 (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
1049 (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02001050 (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001051)};
Joe Hershberger05622192011-10-18 10:06:59 +00001052
Tom Rinie199fb32021-08-03 08:31:56 -04001053our %allow_repeated_words = (
1054 add => '',
1055 added => '',
1056 bad => '',
1057 be => '',
1058);
1059
Joe Hershberger05622192011-10-18 10:06:59 +00001060sub deparenthesize {
1061 my ($string) = @_;
1062 return "" if (!defined($string));
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001063
1064 while ($string =~ /^\s*\(.*\)\s*$/) {
1065 $string =~ s@^\s*\(\s*@@;
1066 $string =~ s@\s*\)\s*$@@;
1067 }
1068
Joe Hershberger05622192011-10-18 10:06:59 +00001069 $string =~ s@\s+@ @g;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001070
Joe Hershberger05622192011-10-18 10:06:59 +00001071 return $string;
1072}
1073
Tom Rini6b9709d2014-02-27 08:27:28 -05001074sub seed_camelcase_file {
1075 my ($file) = @_;
1076
1077 return if (!(-f $file));
1078
1079 local $/;
1080
1081 open(my $include_file, '<', "$file")
1082 or warn "$P: Can't read '$file' $!\n";
1083 my $text = <$include_file>;
1084 close($include_file);
1085
1086 my @lines = split('\n', $text);
1087
1088 foreach my $line (@lines) {
1089 next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/);
1090 if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) {
1091 $camelcase{$1} = 1;
1092 } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) {
1093 $camelcase{$1} = 1;
1094 } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) {
1095 $camelcase{$1} = 1;
1096 }
1097 }
1098}
1099
Tom Rinic57383b2020-06-16 10:29:46 -04001100our %maintained_status = ();
1101
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001102sub is_maintained_obsolete {
1103 my ($filename) = @_;
1104
1105 return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl"));
1106
Tom Rinic57383b2020-06-16 10:29:46 -04001107 if (!exists($maintained_status{$filename})) {
1108 $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
1109 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001110
Tom Rinic57383b2020-06-16 10:29:46 -04001111 return $maintained_status{$filename} =~ /obsolete/i;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001112}
1113
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02001114sub is_SPDX_License_valid {
1115 my ($license) = @_;
1116
Simon Glass587254e2022-01-23 12:55:11 -07001117 return 1 if (!$tree || which("python3") eq "" || !(-x "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02001118
1119 my $root_path = abs_path($root);
Simon Glass587254e2022-01-23 12:55:11 -07001120 my $status = `cd "$root_path"; echo "$license" | scripts/spdxcheck.py -`;
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02001121 return 0 if ($status ne "");
1122 return 1;
1123}
1124
Tom Rini6b9709d2014-02-27 08:27:28 -05001125my $camelcase_seeded = 0;
1126sub seed_camelcase_includes {
1127 return if ($camelcase_seeded);
1128
1129 my $files;
1130 my $camelcase_cache = "";
1131 my @include_files = ();
1132
1133 $camelcase_seeded = 1;
1134
Tom Rinie199fb32021-08-03 08:31:56 -04001135 if (-e "$gitroot") {
Tom Rinic57383b2020-06-16 10:29:46 -04001136 my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`;
Tom Rini6b9709d2014-02-27 08:27:28 -05001137 chomp $git_last_include_commit;
1138 $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
1139 } else {
1140 my $last_mod_date = 0;
1141 $files = `find $root/include -name "*.h"`;
1142 @include_files = split('\n', $files);
1143 foreach my $file (@include_files) {
1144 my $date = POSIX::strftime("%Y%m%d%H%M",
1145 localtime((stat $file)[9]));
1146 $last_mod_date = $date if ($last_mod_date < $date);
1147 }
1148 $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date";
1149 }
1150
1151 if ($camelcase_cache ne "" && -f $camelcase_cache) {
1152 open(my $camelcase_file, '<', "$camelcase_cache")
1153 or warn "$P: Can't read '$camelcase_cache' $!\n";
1154 while (<$camelcase_file>) {
1155 chomp;
1156 $camelcase{$_} = 1;
1157 }
1158 close($camelcase_file);
1159
1160 return;
1161 }
1162
Tom Rinie199fb32021-08-03 08:31:56 -04001163 if (-e "$gitroot") {
Tom Rinic57383b2020-06-16 10:29:46 -04001164 $files = `${git_command} ls-files "include/*.h"`;
Tom Rini6b9709d2014-02-27 08:27:28 -05001165 @include_files = split('\n', $files);
1166 }
1167
1168 foreach my $file (@include_files) {
1169 seed_camelcase_file($file);
1170 }
1171
1172 if ($camelcase_cache ne "") {
1173 unlink glob ".checkpatch-camelcase.*";
1174 open(my $camelcase_file, '>', "$camelcase_cache")
1175 or warn "$P: Can't write '$camelcase_cache' $!\n";
1176 foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) {
1177 print $camelcase_file ("$_\n");
1178 }
1179 close($camelcase_file);
1180 }
1181}
1182
Tom Rinie199fb32021-08-03 08:31:56 -04001183sub git_is_single_file {
1184 my ($filename) = @_;
1185
1186 return 0 if ((which("git") eq "") || !(-e "$gitroot"));
1187
1188 my $output = `${git_command} ls-files -- $filename 2>/dev/null`;
1189 my $count = $output =~ tr/\n//;
1190 return $count eq 1 && $output =~ m{^${filename}$};
1191}
1192
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001193sub git_commit_info {
1194 my ($commit, $id, $desc) = @_;
1195
Tom Rinie199fb32021-08-03 08:31:56 -04001196 return ($id, $desc) if ((which("git") eq "") || !(-e "$gitroot"));
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001197
Tom Rinic57383b2020-06-16 10:29:46 -04001198 my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001199 $output =~ s/^\s*//gm;
1200 my @lines = split("\n", $output);
1201
1202 return ($id, $desc) if ($#lines < 0);
1203
Tom Rinic57383b2020-06-16 10:29:46 -04001204 if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001205# Maybe one day convert this block of bash into something that returns
1206# all matching commit ids, but it's very slow...
1207#
1208# echo "checking commits $1..."
1209# git rev-list --remotes | grep -i "^$1" |
1210# while read line ; do
1211# git log --format='%H %s' -1 $line |
1212# echo "commit $(cut -c 1-12,41-)"
1213# done
Simon Glass587254e2022-01-23 12:55:11 -07001214 } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./ ||
1215 $lines[0] =~ /^fatal: bad object $commit/) {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001216 $id = undef;
1217 } else {
1218 $id = substr($lines[0], 0, 12);
1219 $desc = substr($lines[0], 41);
1220 }
1221
1222 return ($id, $desc);
1223}
1224
Joe Hershberger05622192011-10-18 10:06:59 +00001225$chk_signoff = 0 if ($file);
1226
Joe Hershberger05622192011-10-18 10:06:59 +00001227my @rawlines = ();
1228my @lines = ();
Tom Rini6b9709d2014-02-27 08:27:28 -05001229my @fixed = ();
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001230my @fixed_inserted = ();
1231my @fixed_deleted = ();
Dan Murphyc10e0f52017-01-31 14:15:53 -06001232my $fixlinenr = -1;
1233
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001234# If input is git commits, extract all commits from the commit expressions.
1235# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'.
Tom Rinie199fb32021-08-03 08:31:56 -04001236die "$P: No git repository found\n" if ($git && !-e "$gitroot");
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001237
1238if ($git) {
1239 my @commits = ();
1240 foreach my $commit_expr (@ARGV) {
1241 my $git_range;
1242 if ($commit_expr =~ m/^(.*)-(\d+)$/) {
1243 $git_range = "-$2 $1";
1244 } elsif ($commit_expr =~ m/\.\./) {
1245 $git_range = "$commit_expr";
1246 } else {
1247 $git_range = "-1 $commit_expr";
1248 }
Tom Rinic57383b2020-06-16 10:29:46 -04001249 my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001250 foreach my $line (split(/\n/, $lines)) {
1251 $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
1252 next if (!defined($1) || !defined($2));
1253 my $sha1 = $1;
1254 my $subject = $2;
1255 unshift(@commits, $sha1);
1256 $git_commits{$sha1} = $subject;
1257 }
1258 }
1259 die "$P: no git commits after extraction!\n" if (@commits == 0);
1260 @ARGV = @commits;
1261}
1262
1263my $vname;
Tom Rinic57383b2020-06-16 10:29:46 -04001264$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"};
Joe Hershberger05622192011-10-18 10:06:59 +00001265for my $filename (@ARGV) {
1266 my $FILE;
Tom Rinie199fb32021-08-03 08:31:56 -04001267 my $is_git_file = git_is_single_file($filename);
1268 my $oldfile = $file;
1269 $file = 1 if ($is_git_file);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001270 if ($git) {
1271 open($FILE, '-|', "git format-patch -M --stdout -1 $filename") ||
1272 die "$P: $filename: git format-patch failed - $!\n";
1273 } elsif ($file) {
Joe Hershberger05622192011-10-18 10:06:59 +00001274 open($FILE, '-|', "diff -u /dev/null $filename") ||
1275 die "$P: $filename: diff failed - $!\n";
1276 } elsif ($filename eq '-') {
1277 open($FILE, '<&STDIN');
1278 } else {
1279 open($FILE, '<', "$filename") ||
1280 die "$P: $filename: open failed - $!\n";
1281 }
1282 if ($filename eq '-') {
1283 $vname = 'Your patch';
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001284 } elsif ($git) {
1285 $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")';
Joe Hershberger05622192011-10-18 10:06:59 +00001286 } else {
1287 $vname = $filename;
1288 }
1289 while (<$FILE>) {
1290 chomp;
1291 push(@rawlines, $_);
Tom Rinie199fb32021-08-03 08:31:56 -04001292 $vname = qq("$1") if ($filename eq '-' && $_ =~ m/^Subject:\s+(.+)/i);
Joe Hershberger05622192011-10-18 10:06:59 +00001293 }
1294 close($FILE);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001295
1296 if ($#ARGV > 0 && $quiet == 0) {
1297 print '-' x length($vname) . "\n";
1298 print "$vname\n";
1299 print '-' x length($vname) . "\n";
1300 }
1301
Joe Hershberger05622192011-10-18 10:06:59 +00001302 if (!process($filename)) {
1303 $exit = 1;
1304 }
1305 @rawlines = ();
1306 @lines = ();
Tom Rini6b9709d2014-02-27 08:27:28 -05001307 @fixed = ();
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001308 @fixed_inserted = ();
1309 @fixed_deleted = ();
1310 $fixlinenr = -1;
1311 @modifierListFile = ();
1312 @typeListFile = ();
1313 build_types();
Tom Rinie199fb32021-08-03 08:31:56 -04001314 $file = $oldfile if ($is_git_file);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001315}
1316
1317if (!$quiet) {
1318 hash_show_words(\%use_type, "Used");
1319 hash_show_words(\%ignore_type, "Ignored");
1320
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02001321 if (!$perl_version_ok) {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001322 print << "EOM"
1323
1324NOTE: perl $^V is not modern enough to detect all possible issues.
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02001325 An upgrade to at least perl $minimum_perl_version is suggested.
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001326EOM
1327 }
1328 if ($exit) {
1329 print << "EOM"
1330
1331NOTE: If any of the errors are false positives, please report
1332 them to the maintainer, see CHECKPATCH in MAINTAINERS.
1333EOM
1334 }
Joe Hershberger05622192011-10-18 10:06:59 +00001335}
1336
1337exit($exit);
1338
1339sub top_of_kernel_tree {
1340 my ($root) = @_;
1341
1342 my @tree_check = (
Tom Rini6b9709d2014-02-27 08:27:28 -05001343 "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
Joe Hershberger05622192011-10-18 10:06:59 +00001344 "README", "Documentation", "arch", "include", "drivers",
1345 "fs", "init", "ipc", "kernel", "lib", "scripts",
1346 );
1347
1348 foreach my $check (@tree_check) {
1349 if (! -e $root . '/' . $check) {
1350 return 0;
1351 }
1352 }
1353 return 1;
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00001354}
Joe Hershberger05622192011-10-18 10:06:59 +00001355
1356sub parse_email {
1357 my ($formatted_email) = @_;
1358
1359 my $name = "";
Tom Rinie199fb32021-08-03 08:31:56 -04001360 my $quoted = "";
Tom Rinic57383b2020-06-16 10:29:46 -04001361 my $name_comment = "";
Joe Hershberger05622192011-10-18 10:06:59 +00001362 my $address = "";
1363 my $comment = "";
1364
1365 if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) {
1366 $name = $1;
1367 $address = $2;
1368 $comment = $3 if defined $3;
1369 } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) {
1370 $address = $1;
1371 $comment = $2 if defined $2;
1372 } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) {
1373 $address = $1;
1374 $comment = $2 if defined $2;
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02001375 $formatted_email =~ s/\Q$address\E.*$//;
Joe Hershberger05622192011-10-18 10:06:59 +00001376 $name = $formatted_email;
Tom Rini6b9709d2014-02-27 08:27:28 -05001377 $name = trim($name);
Joe Hershberger05622192011-10-18 10:06:59 +00001378 $name =~ s/^\"|\"$//g;
1379 # If there's a name left after stripping spaces and
1380 # leading quotes, and the address doesn't have both
1381 # leading and trailing angle brackets, the address
1382 # is invalid. ie:
1383 # "joe smith joe@smith.com" bad
1384 # "joe smith <joe@smith.com" bad
1385 if ($name ne "" && $address !~ /^<[^>]+>$/) {
1386 $name = "";
1387 $address = "";
1388 $comment = "";
1389 }
1390 }
1391
Tom Rinie199fb32021-08-03 08:31:56 -04001392 # Extract comments from names excluding quoted parts
1393 # "John D. (Doe)" - Do not extract
1394 if ($name =~ s/\"(.+)\"//) {
1395 $quoted = $1;
Tom Rinic57383b2020-06-16 10:29:46 -04001396 }
Tom Rinie199fb32021-08-03 08:31:56 -04001397 while ($name =~ s/\s*($balanced_parens)\s*/ /) {
1398 $name_comment .= trim($1);
1399 }
1400 $name =~ s/^[ \"]+|[ \"]+$//g;
1401 $name = trim("$quoted $name");
1402
Tom Rini6b9709d2014-02-27 08:27:28 -05001403 $address = trim($address);
Joe Hershberger05622192011-10-18 10:06:59 +00001404 $address =~ s/^\<|\>$//g;
Tom Rinie199fb32021-08-03 08:31:56 -04001405 $comment = trim($comment);
Joe Hershberger05622192011-10-18 10:06:59 +00001406
1407 if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
1408 $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
1409 $name = "\"$name\"";
1410 }
1411
Tom Rinic57383b2020-06-16 10:29:46 -04001412 return ($name, $name_comment, $address, $comment);
Joe Hershberger05622192011-10-18 10:06:59 +00001413}
1414
1415sub format_email {
Tom Rinie199fb32021-08-03 08:31:56 -04001416 my ($name, $name_comment, $address, $comment) = @_;
Joe Hershberger05622192011-10-18 10:06:59 +00001417
1418 my $formatted_email;
1419
Tom Rinie199fb32021-08-03 08:31:56 -04001420 $name =~ s/^[ \"]+|[ \"]+$//g;
Tom Rini6b9709d2014-02-27 08:27:28 -05001421 $address = trim($address);
Tom Rinie199fb32021-08-03 08:31:56 -04001422 $address =~ s/(?:\.|\,|\")+$//; ##trailing commas, dots or quotes
Joe Hershberger05622192011-10-18 10:06:59 +00001423
1424 if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
1425 $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
1426 $name = "\"$name\"";
1427 }
1428
Tom Rinie199fb32021-08-03 08:31:56 -04001429 $name_comment = trim($name_comment);
1430 $name_comment = " $name_comment" if ($name_comment ne "");
1431 $comment = trim($comment);
1432 $comment = " $comment" if ($comment ne "");
1433
Joe Hershberger05622192011-10-18 10:06:59 +00001434 if ("$name" eq "") {
1435 $formatted_email = "$address";
1436 } else {
Tom Rinie199fb32021-08-03 08:31:56 -04001437 $formatted_email = "$name$name_comment <$address>";
Joe Hershberger05622192011-10-18 10:06:59 +00001438 }
Tom Rinie199fb32021-08-03 08:31:56 -04001439 $formatted_email .= "$comment";
Joe Hershberger05622192011-10-18 10:06:59 +00001440 return $formatted_email;
1441}
1442
Tom Rinic57383b2020-06-16 10:29:46 -04001443sub reformat_email {
1444 my ($email) = @_;
1445
1446 my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);
Tom Rinie199fb32021-08-03 08:31:56 -04001447 return format_email($email_name, $name_comment, $email_address, $comment);
Tom Rinic57383b2020-06-16 10:29:46 -04001448}
1449
1450sub same_email_addresses {
1451 my ($email1, $email2) = @_;
1452
1453 my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1);
1454 my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2);
1455
1456 return $email1_name eq $email2_name &&
Tom Rinie199fb32021-08-03 08:31:56 -04001457 $email1_address eq $email2_address &&
1458 $name1_comment eq $name2_comment &&
1459 $comment1 eq $comment2;
Tom Rinic57383b2020-06-16 10:29:46 -04001460}
1461
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001462sub which {
1463 my ($bin) = @_;
1464
1465 foreach my $path (split(/:/, $ENV{PATH})) {
1466 if (-e "$path/$bin") {
1467 return "$path/$bin";
1468 }
1469 }
1470
1471 return "";
1472}
1473
Joe Hershberger05622192011-10-18 10:06:59 +00001474sub which_conf {
1475 my ($conf) = @_;
1476
1477 foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
1478 if (-e "$path/$conf") {
1479 return "$path/$conf";
1480 }
1481 }
1482
1483 return "";
1484}
1485
1486sub expand_tabs {
1487 my ($str) = @_;
1488
1489 my $res = '';
1490 my $n = 0;
1491 for my $c (split(//, $str)) {
1492 if ($c eq "\t") {
1493 $res .= ' ';
1494 $n++;
Tom Rinic57383b2020-06-16 10:29:46 -04001495 for (; ($n % $tabsize) != 0; $n++) {
Joe Hershberger05622192011-10-18 10:06:59 +00001496 $res .= ' ';
1497 }
1498 next;
1499 }
1500 $res .= $c;
1501 $n++;
1502 }
1503
1504 return $res;
1505}
1506sub copy_spacing {
1507 (my $res = shift) =~ tr/\t/ /c;
1508 return $res;
1509}
1510
1511sub line_stats {
1512 my ($line) = @_;
1513
1514 # Drop the diff line leader and expand tabs
1515 $line =~ s/^.//;
1516 $line = expand_tabs($line);
1517
1518 # Pick the indent from the front of the line.
1519 my ($white) = ($line =~ /^(\s*)/);
1520
1521 return (length($line), length($white));
1522}
1523
1524my $sanitise_quote = '';
1525
1526sub sanitise_line_reset {
1527 my ($in_comment) = @_;
1528
1529 if ($in_comment) {
1530 $sanitise_quote = '*/';
1531 } else {
1532 $sanitise_quote = '';
1533 }
1534}
1535sub sanitise_line {
1536 my ($line) = @_;
1537
1538 my $res = '';
1539 my $l = '';
1540
1541 my $qlen = 0;
1542 my $off = 0;
1543 my $c;
1544
1545 # Always copy over the diff marker.
1546 $res = substr($line, 0, 1);
1547
1548 for ($off = 1; $off < length($line); $off++) {
1549 $c = substr($line, $off, 1);
1550
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02001551 # Comments we are whacking completely including the begin
Joe Hershberger05622192011-10-18 10:06:59 +00001552 # and end, all to $;.
1553 if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
1554 $sanitise_quote = '*/';
1555
1556 substr($res, $off, 2, "$;$;");
1557 $off++;
1558 next;
1559 }
1560 if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
1561 $sanitise_quote = '';
1562 substr($res, $off, 2, "$;$;");
1563 $off++;
1564 next;
1565 }
1566 if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
1567 $sanitise_quote = '//';
1568
1569 substr($res, $off, 2, $sanitise_quote);
1570 $off++;
1571 next;
1572 }
1573
1574 # A \ in a string means ignore the next character.
1575 if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
1576 $c eq "\\") {
1577 substr($res, $off, 2, 'XX');
1578 $off++;
1579 next;
1580 }
1581 # Regular quotes.
1582 if ($c eq "'" || $c eq '"') {
1583 if ($sanitise_quote eq '') {
1584 $sanitise_quote = $c;
1585
1586 substr($res, $off, 1, $c);
1587 next;
1588 } elsif ($sanitise_quote eq $c) {
1589 $sanitise_quote = '';
1590 }
1591 }
1592
1593 #print "c<$c> SQ<$sanitise_quote>\n";
1594 if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
1595 substr($res, $off, 1, $;);
1596 } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
1597 substr($res, $off, 1, $;);
1598 } elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
1599 substr($res, $off, 1, 'X');
1600 } else {
1601 substr($res, $off, 1, $c);
1602 }
1603 }
1604
1605 if ($sanitise_quote eq '//') {
1606 $sanitise_quote = '';
1607 }
1608
1609 # The pathname on a #include may be surrounded by '<' and '>'.
1610 if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
1611 my $clean = 'X' x length($1);
1612 $res =~ s@\<.*\>@<$clean>@;
1613
1614 # The whole of a #error is a string.
1615 } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
1616 my $clean = 'X' x length($1);
1617 $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
1618 }
1619
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001620 if ($allow_c99_comments && $res =~ m@(//.*$)@) {
1621 my $match = $1;
1622 $res =~ s/\Q$match\E/"$;" x length($match)/e;
1623 }
1624
Joe Hershberger05622192011-10-18 10:06:59 +00001625 return $res;
1626}
1627
Tom Rini6b9709d2014-02-27 08:27:28 -05001628sub get_quoted_string {
1629 my ($line, $rawline) = @_;
1630
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02001631 return "" if (!defined($line) || !defined($rawline));
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02001632 return "" if ($line !~ m/($String)/g);
Tom Rini6b9709d2014-02-27 08:27:28 -05001633 return substr($rawline, $-[0], $+[0] - $-[0]);
1634}
1635
Joe Hershberger05622192011-10-18 10:06:59 +00001636sub ctx_statement_block {
1637 my ($linenr, $remain, $off) = @_;
1638 my $line = $linenr - 1;
1639 my $blk = '';
1640 my $soff = $off;
1641 my $coff = $off - 1;
1642 my $coff_set = 0;
1643
1644 my $loff = 0;
1645
1646 my $type = '';
1647 my $level = 0;
1648 my @stack = ();
1649 my $p;
1650 my $c;
1651 my $len = 0;
1652
1653 my $remainder;
1654 while (1) {
1655 @stack = (['', 0]) if ($#stack == -1);
1656
1657 #warn "CSB: blk<$blk> remain<$remain>\n";
1658 # If we are about to drop off the end, pull in more
1659 # context.
1660 if ($off >= $len) {
1661 for (; $remain > 0; $line++) {
1662 last if (!defined $lines[$line]);
1663 next if ($lines[$line] =~ /^-/);
1664 $remain--;
1665 $loff = $len;
1666 $blk .= $lines[$line] . "\n";
1667 $len = length($blk);
1668 $line++;
1669 last;
1670 }
1671 # Bail if there is no further context.
1672 #warn "CSB: blk<$blk> off<$off> len<$len>\n";
1673 if ($off >= $len) {
1674 last;
1675 }
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00001676 if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) {
1677 $level++;
1678 $type = '#';
1679 }
Joe Hershberger05622192011-10-18 10:06:59 +00001680 }
1681 $p = $c;
1682 $c = substr($blk, $off, 1);
1683 $remainder = substr($blk, $off);
1684
1685 #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
1686
1687 # Handle nested #if/#else.
1688 if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
1689 push(@stack, [ $type, $level ]);
1690 } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
1691 ($type, $level) = @{$stack[$#stack - 1]};
1692 } elsif ($remainder =~ /^#\s*endif\b/) {
1693 ($type, $level) = @{pop(@stack)};
1694 }
1695
1696 # Statement ends at the ';' or a close '}' at the
1697 # outermost level.
1698 if ($level == 0 && $c eq ';') {
1699 last;
1700 }
1701
1702 # An else is really a conditional as long as its not else if
1703 if ($level == 0 && $coff_set == 0 &&
1704 (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
1705 $remainder =~ /^(else)(?:\s|{)/ &&
1706 $remainder !~ /^else\s+if\b/) {
1707 $coff = $off + length($1) - 1;
1708 $coff_set = 1;
1709 #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
1710 #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
1711 }
1712
1713 if (($type eq '' || $type eq '(') && $c eq '(') {
1714 $level++;
1715 $type = '(';
1716 }
1717 if ($type eq '(' && $c eq ')') {
1718 $level--;
1719 $type = ($level != 0)? '(' : '';
1720
1721 if ($level == 0 && $coff < $soff) {
1722 $coff = $off;
1723 $coff_set = 1;
1724 #warn "CSB: mark coff<$coff>\n";
1725 }
1726 }
1727 if (($type eq '' || $type eq '{') && $c eq '{') {
1728 $level++;
1729 $type = '{';
1730 }
1731 if ($type eq '{' && $c eq '}') {
1732 $level--;
1733 $type = ($level != 0)? '{' : '';
1734
1735 if ($level == 0) {
1736 if (substr($blk, $off + 1, 1) eq ';') {
1737 $off++;
1738 }
1739 last;
1740 }
1741 }
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00001742 # Preprocessor commands end at the newline unless escaped.
1743 if ($type eq '#' && $c eq "\n" && $p ne "\\") {
1744 $level--;
1745 $type = '';
1746 $off++;
1747 last;
1748 }
Joe Hershberger05622192011-10-18 10:06:59 +00001749 $off++;
1750 }
1751 # We are truly at the end, so shuffle to the next line.
1752 if ($off == $len) {
1753 $loff = $len + 1;
1754 $line++;
1755 $remain--;
1756 }
1757
1758 my $statement = substr($blk, $soff, $off - $soff + 1);
1759 my $condition = substr($blk, $soff, $coff - $soff + 1);
1760
1761 #warn "STATEMENT<$statement>\n";
1762 #warn "CONDITION<$condition>\n";
1763
1764 #print "coff<$coff> soff<$off> loff<$loff>\n";
1765
1766 return ($statement, $condition,
1767 $line, $remain + 1, $off - $loff + 1, $level);
1768}
1769
1770sub statement_lines {
1771 my ($stmt) = @_;
1772
1773 # Strip the diff line prefixes and rip blank lines at start and end.
1774 $stmt =~ s/(^|\n)./$1/g;
1775 $stmt =~ s/^\s*//;
1776 $stmt =~ s/\s*$//;
1777
1778 my @stmt_lines = ($stmt =~ /\n/g);
1779
1780 return $#stmt_lines + 2;
1781}
1782
1783sub statement_rawlines {
1784 my ($stmt) = @_;
1785
1786 my @stmt_lines = ($stmt =~ /\n/g);
1787
1788 return $#stmt_lines + 2;
1789}
1790
1791sub statement_block_size {
1792 my ($stmt) = @_;
1793
1794 $stmt =~ s/(^|\n)./$1/g;
1795 $stmt =~ s/^\s*{//;
1796 $stmt =~ s/}\s*$//;
1797 $stmt =~ s/^\s*//;
1798 $stmt =~ s/\s*$//;
1799
1800 my @stmt_lines = ($stmt =~ /\n/g);
1801 my @stmt_statements = ($stmt =~ /;/g);
1802
1803 my $stmt_lines = $#stmt_lines + 2;
1804 my $stmt_statements = $#stmt_statements + 1;
1805
1806 if ($stmt_lines > $stmt_statements) {
1807 return $stmt_lines;
1808 } else {
1809 return $stmt_statements;
1810 }
1811}
1812
1813sub ctx_statement_full {
1814 my ($linenr, $remain, $off) = @_;
1815 my ($statement, $condition, $level);
1816
1817 my (@chunks);
1818
1819 # Grab the first conditional/block pair.
1820 ($statement, $condition, $linenr, $remain, $off, $level) =
1821 ctx_statement_block($linenr, $remain, $off);
1822 #print "F: c<$condition> s<$statement> remain<$remain>\n";
1823 push(@chunks, [ $condition, $statement ]);
1824 if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
1825 return ($level, $linenr, @chunks);
1826 }
1827
1828 # Pull in the following conditional/block pairs and see if they
1829 # could continue the statement.
1830 for (;;) {
1831 ($statement, $condition, $linenr, $remain, $off, $level) =
1832 ctx_statement_block($linenr, $remain, $off);
1833 #print "C: c<$condition> s<$statement> remain<$remain>\n";
1834 last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
1835 #print "C: push\n";
1836 push(@chunks, [ $condition, $statement ]);
1837 }
1838
1839 return ($level, $linenr, @chunks);
1840}
1841
1842sub ctx_block_get {
1843 my ($linenr, $remain, $outer, $open, $close, $off) = @_;
1844 my $line;
1845 my $start = $linenr - 1;
1846 my $blk = '';
1847 my @o;
1848 my @c;
1849 my @res = ();
1850
1851 my $level = 0;
1852 my @stack = ($level);
1853 for ($line = $start; $remain > 0; $line++) {
1854 next if ($rawlines[$line] =~ /^-/);
1855 $remain--;
1856
1857 $blk .= $rawlines[$line];
1858
1859 # Handle nested #if/#else.
1860 if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
1861 push(@stack, $level);
1862 } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
1863 $level = $stack[$#stack - 1];
1864 } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
1865 $level = pop(@stack);
1866 }
1867
1868 foreach my $c (split(//, $lines[$line])) {
1869 ##print "C<$c>L<$level><$open$close>O<$off>\n";
1870 if ($off > 0) {
1871 $off--;
1872 next;
1873 }
1874
1875 if ($c eq $close && $level > 0) {
1876 $level--;
1877 last if ($level == 0);
1878 } elsif ($c eq $open) {
1879 $level++;
1880 }
1881 }
1882
1883 if (!$outer || $level <= 1) {
1884 push(@res, $rawlines[$line]);
1885 }
1886
1887 last if ($level == 0);
1888 }
1889
1890 return ($level, @res);
1891}
1892sub ctx_block_outer {
1893 my ($linenr, $remain) = @_;
1894
1895 my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
1896 return @r;
1897}
1898sub ctx_block {
1899 my ($linenr, $remain) = @_;
1900
1901 my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
1902 return @r;
1903}
1904sub ctx_statement {
1905 my ($linenr, $remain, $off) = @_;
1906
1907 my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
1908 return @r;
1909}
1910sub ctx_block_level {
1911 my ($linenr, $remain) = @_;
1912
1913 return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
1914}
1915sub ctx_statement_level {
1916 my ($linenr, $remain, $off) = @_;
1917
1918 return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
1919}
1920
1921sub ctx_locate_comment {
1922 my ($first_line, $end_line) = @_;
1923
Tom Rinie199fb32021-08-03 08:31:56 -04001924 # If c99 comment on the current line, or the line before or after
1925 my ($current_comment) = ($rawlines[$end_line - 1] =~ m@^\+.*(//.*$)@);
1926 return $current_comment if (defined $current_comment);
1927 ($current_comment) = ($rawlines[$end_line - 2] =~ m@^[\+ ].*(//.*$)@);
1928 return $current_comment if (defined $current_comment);
1929 ($current_comment) = ($rawlines[$end_line] =~ m@^[\+ ].*(//.*$)@);
1930 return $current_comment if (defined $current_comment);
1931
Joe Hershberger05622192011-10-18 10:06:59 +00001932 # Catch a comment on the end of the line itself.
Tom Rinie199fb32021-08-03 08:31:56 -04001933 ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
Joe Hershberger05622192011-10-18 10:06:59 +00001934 return $current_comment if (defined $current_comment);
1935
1936 # Look through the context and try and figure out if there is a
1937 # comment.
1938 my $in_comment = 0;
1939 $current_comment = '';
1940 for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
1941 my $line = $rawlines[$linenr - 1];
1942 #warn " $line\n";
1943 if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
1944 $in_comment = 1;
1945 }
1946 if ($line =~ m@/\*@) {
1947 $in_comment = 1;
1948 }
1949 if (!$in_comment && $current_comment ne '') {
1950 $current_comment = '';
1951 }
1952 $current_comment .= $line . "\n" if ($in_comment);
1953 if ($line =~ m@\*/@) {
1954 $in_comment = 0;
1955 }
1956 }
1957
1958 chomp($current_comment);
1959 return($current_comment);
1960}
1961sub ctx_has_comment {
1962 my ($first_line, $end_line) = @_;
1963 my $cmt = ctx_locate_comment($first_line, $end_line);
1964
1965 ##print "LINE: $rawlines[$end_line - 1 ]\n";
1966 ##print "CMMT: $cmt\n";
1967
1968 return ($cmt ne '');
1969}
1970
1971sub raw_line {
1972 my ($linenr, $cnt) = @_;
1973
1974 my $offset = $linenr - 1;
1975 $cnt++;
1976
1977 my $line;
1978 while ($cnt) {
1979 $line = $rawlines[$offset++];
1980 next if (defined($line) && $line =~ /^-/);
1981 $cnt--;
1982 }
1983
1984 return $line;
1985}
1986
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02001987sub get_stat_real {
1988 my ($linenr, $lc) = @_;
1989
1990 my $stat_real = raw_line($linenr, 0);
1991 for (my $count = $linenr + 1; $count <= $lc; $count++) {
1992 $stat_real = $stat_real . "\n" . raw_line($count, 0);
1993 }
1994
1995 return $stat_real;
1996}
1997
1998sub get_stat_here {
1999 my ($linenr, $cnt, $here) = @_;
2000
2001 my $herectx = $here . "\n";
2002 for (my $n = 0; $n < $cnt; $n++) {
2003 $herectx .= raw_line($linenr, $n) . "\n";
2004 }
2005
2006 return $herectx;
2007}
2008
Joe Hershberger05622192011-10-18 10:06:59 +00002009sub cat_vet {
2010 my ($vet) = @_;
2011 my ($res, $coded);
2012
2013 $res = '';
2014 while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
2015 $res .= $1;
2016 if ($2 ne '') {
2017 $coded = sprintf("^%c", unpack('C', $2) + 64);
2018 $res .= $coded;
2019 }
2020 }
2021 $res =~ s/$/\$/;
2022
2023 return $res;
2024}
2025
2026my $av_preprocessor = 0;
2027my $av_pending;
2028my @av_paren_type;
2029my $av_pend_colon;
2030
2031sub annotate_reset {
2032 $av_preprocessor = 0;
2033 $av_pending = '_';
2034 @av_paren_type = ('E');
2035 $av_pend_colon = 'O';
2036}
2037
2038sub annotate_values {
2039 my ($stream, $type) = @_;
2040
2041 my $res;
2042 my $var = '_' x length($stream);
2043 my $cur = $stream;
2044
2045 print "$stream\n" if ($dbg_values > 1);
2046
2047 while (length($cur)) {
2048 @av_paren_type = ('E') if ($#av_paren_type < 0);
2049 print " <" . join('', @av_paren_type) .
2050 "> <$type> <$av_pending>" if ($dbg_values > 1);
2051 if ($cur =~ /^(\s+)/o) {
2052 print "WS($1)\n" if ($dbg_values > 1);
2053 if ($1 =~ /\n/ && $av_preprocessor) {
2054 $type = pop(@av_paren_type);
2055 $av_preprocessor = 0;
2056 }
2057
2058 } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
2059 print "CAST($1)\n" if ($dbg_values > 1);
2060 push(@av_paren_type, $type);
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002061 $type = 'c';
Joe Hershberger05622192011-10-18 10:06:59 +00002062
2063 } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
2064 print "DECLARE($1)\n" if ($dbg_values > 1);
2065 $type = 'T';
2066
2067 } elsif ($cur =~ /^($Modifier)\s*/) {
2068 print "MODIFIER($1)\n" if ($dbg_values > 1);
2069 $type = 'T';
2070
2071 } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
2072 print "DEFINE($1,$2)\n" if ($dbg_values > 1);
2073 $av_preprocessor = 1;
2074 push(@av_paren_type, $type);
2075 if ($2 ne '') {
2076 $av_pending = 'N';
2077 }
2078 $type = 'E';
2079
2080 } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
2081 print "UNDEF($1)\n" if ($dbg_values > 1);
2082 $av_preprocessor = 1;
2083 push(@av_paren_type, $type);
2084
2085 } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
2086 print "PRE_START($1)\n" if ($dbg_values > 1);
2087 $av_preprocessor = 1;
2088
2089 push(@av_paren_type, $type);
2090 push(@av_paren_type, $type);
2091 $type = 'E';
2092
2093 } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
2094 print "PRE_RESTART($1)\n" if ($dbg_values > 1);
2095 $av_preprocessor = 1;
2096
2097 push(@av_paren_type, $av_paren_type[$#av_paren_type]);
2098
2099 $type = 'E';
2100
2101 } elsif ($cur =~ /^(\#\s*(?:endif))/o) {
2102 print "PRE_END($1)\n" if ($dbg_values > 1);
2103
2104 $av_preprocessor = 1;
2105
2106 # Assume all arms of the conditional end as this
2107 # one does, and continue as if the #endif was not here.
2108 pop(@av_paren_type);
2109 push(@av_paren_type, $type);
2110 $type = 'E';
2111
2112 } elsif ($cur =~ /^(\\\n)/o) {
2113 print "PRECONT($1)\n" if ($dbg_values > 1);
2114
2115 } elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
2116 print "ATTR($1)\n" if ($dbg_values > 1);
2117 $av_pending = $type;
2118 $type = 'N';
2119
2120 } elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
2121 print "SIZEOF($1)\n" if ($dbg_values > 1);
2122 if (defined $2) {
2123 $av_pending = 'V';
2124 }
2125 $type = 'N';
2126
2127 } elsif ($cur =~ /^(if|while|for)\b/o) {
2128 print "COND($1)\n" if ($dbg_values > 1);
2129 $av_pending = 'E';
2130 $type = 'N';
2131
2132 } elsif ($cur =~/^(case)/o) {
2133 print "CASE($1)\n" if ($dbg_values > 1);
2134 $av_pend_colon = 'C';
2135 $type = 'N';
2136
2137 } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
2138 print "KEYWORD($1)\n" if ($dbg_values > 1);
2139 $type = 'N';
2140
2141 } elsif ($cur =~ /^(\()/o) {
2142 print "PAREN('$1')\n" if ($dbg_values > 1);
2143 push(@av_paren_type, $av_pending);
2144 $av_pending = '_';
2145 $type = 'N';
2146
2147 } elsif ($cur =~ /^(\))/o) {
2148 my $new_type = pop(@av_paren_type);
2149 if ($new_type ne '_') {
2150 $type = $new_type;
2151 print "PAREN('$1') -> $type\n"
2152 if ($dbg_values > 1);
2153 } else {
2154 print "PAREN('$1')\n" if ($dbg_values > 1);
2155 }
2156
2157 } elsif ($cur =~ /^($Ident)\s*\(/o) {
2158 print "FUNC($1)\n" if ($dbg_values > 1);
2159 $type = 'V';
2160 $av_pending = 'V';
2161
2162 } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
2163 if (defined $2 && $type eq 'C' || $type eq 'T') {
2164 $av_pend_colon = 'B';
2165 } elsif ($type eq 'E') {
2166 $av_pend_colon = 'L';
2167 }
2168 print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
2169 $type = 'V';
2170
2171 } elsif ($cur =~ /^($Ident|$Constant)/o) {
2172 print "IDENT($1)\n" if ($dbg_values > 1);
2173 $type = 'V';
2174
2175 } elsif ($cur =~ /^($Assignment)/o) {
2176 print "ASSIGN($1)\n" if ($dbg_values > 1);
2177 $type = 'N';
2178
2179 } elsif ($cur =~/^(;|{|})/) {
2180 print "END($1)\n" if ($dbg_values > 1);
2181 $type = 'E';
2182 $av_pend_colon = 'O';
2183
2184 } elsif ($cur =~/^(,)/) {
2185 print "COMMA($1)\n" if ($dbg_values > 1);
2186 $type = 'C';
2187
2188 } elsif ($cur =~ /^(\?)/o) {
2189 print "QUESTION($1)\n" if ($dbg_values > 1);
2190 $type = 'N';
2191
2192 } elsif ($cur =~ /^(:)/o) {
2193 print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
2194
2195 substr($var, length($res), 1, $av_pend_colon);
2196 if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
2197 $type = 'E';
2198 } else {
2199 $type = 'N';
2200 }
2201 $av_pend_colon = 'O';
2202
2203 } elsif ($cur =~ /^(\[)/o) {
2204 print "CLOSE($1)\n" if ($dbg_values > 1);
2205 $type = 'N';
2206
2207 } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
2208 my $variant;
2209
2210 print "OPV($1)\n" if ($dbg_values > 1);
2211 if ($type eq 'V') {
2212 $variant = 'B';
2213 } else {
2214 $variant = 'U';
2215 }
2216
2217 substr($var, length($res), 1, $variant);
2218 $type = 'N';
2219
2220 } elsif ($cur =~ /^($Operators)/o) {
2221 print "OP($1)\n" if ($dbg_values > 1);
2222 if ($1 ne '++' && $1 ne '--') {
2223 $type = 'N';
2224 }
2225
2226 } elsif ($cur =~ /(^.)/o) {
2227 print "C($1)\n" if ($dbg_values > 1);
2228 }
2229 if (defined $1) {
2230 $cur = substr($cur, length($1));
2231 $res .= $type x length($1);
2232 }
2233 }
2234
2235 return ($res, $var);
2236}
2237
2238sub possible {
2239 my ($possible, $line) = @_;
2240 my $notPermitted = qr{(?:
2241 ^(?:
2242 $Modifier|
2243 $Storage|
2244 $Type|
2245 DEFINE_\S+
2246 )$|
2247 ^(?:
2248 goto|
2249 return|
2250 case|
2251 else|
2252 asm|__asm__|
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002253 do|
2254 \#|
2255 \#\#|
Joe Hershberger05622192011-10-18 10:06:59 +00002256 )(?:\s|$)|
2257 ^(?:typedef|struct|enum)\b
2258 )}x;
2259 warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
2260 if ($possible !~ $notPermitted) {
2261 # Check for modifiers.
2262 $possible =~ s/\s*$Storage\s*//g;
2263 $possible =~ s/\s*$Sparse\s*//g;
2264 if ($possible =~ /^\s*$/) {
2265
2266 } elsif ($possible =~ /\s/) {
2267 $possible =~ s/\s*$Type\s*//g;
2268 for my $modifier (split(' ', $possible)) {
2269 if ($modifier !~ $notPermitted) {
2270 warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002271 push(@modifierListFile, $modifier);
Joe Hershberger05622192011-10-18 10:06:59 +00002272 }
2273 }
2274
2275 } else {
2276 warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002277 push(@typeListFile, $possible);
Joe Hershberger05622192011-10-18 10:06:59 +00002278 }
2279 build_types();
2280 } else {
2281 warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
2282 }
2283}
2284
2285my $prefix = '';
2286
2287sub show_type {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002288 my ($type) = @_;
Tom Rini6b9709d2014-02-27 08:27:28 -05002289
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002290 $type =~ tr/[a-z]/[A-Z]/;
2291
2292 return defined $use_type{$type} if (scalar keys %use_type > 0);
2293
2294 return !defined $ignore_type{$type};
Joe Hershberger05622192011-10-18 10:06:59 +00002295}
2296
2297sub report {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002298 my ($level, $type, $msg) = @_;
2299
2300 if (!show_type($type) ||
2301 (defined $tst_only && $msg !~ /\Q$tst_only\E/)) {
Joe Hershberger05622192011-10-18 10:06:59 +00002302 return 0;
2303 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002304 my $output = '';
2305 if ($color) {
2306 if ($level eq 'ERROR') {
2307 $output .= RED;
2308 } elsif ($level eq 'WARNING') {
2309 $output .= YELLOW;
2310 } else {
2311 $output .= GREEN;
2312 }
Joe Hershberger05622192011-10-18 10:06:59 +00002313 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002314 $output .= $prefix . $level . ':';
2315 if ($show_types) {
2316 $output .= BLUE if ($color);
2317 $output .= "$type:";
2318 }
2319 $output .= RESET if ($color);
2320 $output .= ' ' . $msg . "\n";
Joe Hershberger05622192011-10-18 10:06:59 +00002321
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002322 if ($showfile) {
2323 my @lines = split("\n", $output, -1);
2324 splice(@lines, 1, 1);
2325 $output = join("\n", @lines);
2326 }
Tom Rinie199fb32021-08-03 08:31:56 -04002327
2328 if ($terse) {
2329 $output = (split('\n', $output))[0] . "\n";
2330 }
2331
2332 if ($verbose && exists($verbose_messages{$type}) &&
2333 !exists($verbose_emitted{$type})) {
2334 $output .= $verbose_messages{$type} . "\n\n";
2335 $verbose_emitted{$type} = 1;
2336 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002337
2338 push(our @report, $output);
Joe Hershberger05622192011-10-18 10:06:59 +00002339
2340 return 1;
2341}
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002342
Joe Hershberger05622192011-10-18 10:06:59 +00002343sub report_dump {
2344 our @report;
2345}
2346
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002347sub fixup_current_range {
2348 my ($lineRef, $offset, $length) = @_;
2349
2350 if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) {
2351 my $o = $1;
2352 my $l = $2;
2353 my $no = $o + $offset;
2354 my $nl = $l + $length;
2355 $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/;
2356 }
2357}
2358
2359sub fix_inserted_deleted_lines {
2360 my ($linesRef, $insertedRef, $deletedRef) = @_;
2361
2362 my $range_last_linenr = 0;
2363 my $delta_offset = 0;
2364
2365 my $old_linenr = 0;
2366 my $new_linenr = 0;
2367
2368 my $next_insert = 0;
2369 my $next_delete = 0;
2370
2371 my @lines = ();
2372
2373 my $inserted = @{$insertedRef}[$next_insert++];
2374 my $deleted = @{$deletedRef}[$next_delete++];
2375
2376 foreach my $old_line (@{$linesRef}) {
2377 my $save_line = 1;
2378 my $line = $old_line; #don't modify the array
2379 if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename
2380 $delta_offset = 0;
2381 } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk
2382 $range_last_linenr = $new_linenr;
2383 fixup_current_range(\$line, $delta_offset, 0);
2384 }
2385
2386 while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) {
2387 $deleted = @{$deletedRef}[$next_delete++];
2388 $save_line = 0;
2389 fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1);
2390 }
2391
2392 while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) {
2393 push(@lines, ${$inserted}{'LINE'});
2394 $inserted = @{$insertedRef}[$next_insert++];
2395 $new_linenr++;
2396 fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1);
2397 }
2398
2399 if ($save_line) {
2400 push(@lines, $line);
2401 $new_linenr++;
2402 }
2403
2404 $old_linenr++;
2405 }
2406
2407 return @lines;
2408}
2409
2410sub fix_insert_line {
2411 my ($linenr, $line) = @_;
2412
2413 my $inserted = {
2414 LINENR => $linenr,
2415 LINE => $line,
2416 };
2417 push(@fixed_inserted, $inserted);
2418}
2419
2420sub fix_delete_line {
2421 my ($linenr, $line) = @_;
2422
2423 my $deleted = {
2424 LINENR => $linenr,
2425 LINE => $line,
2426 };
2427
2428 push(@fixed_deleted, $deleted);
2429}
2430
Joe Hershberger05622192011-10-18 10:06:59 +00002431sub ERROR {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002432 my ($type, $msg) = @_;
2433
2434 if (report("ERROR", $type, $msg)) {
Joe Hershberger05622192011-10-18 10:06:59 +00002435 our $clean = 0;
2436 our $cnt_error++;
Tom Rini6b9709d2014-02-27 08:27:28 -05002437 return 1;
Joe Hershberger05622192011-10-18 10:06:59 +00002438 }
Tom Rini6b9709d2014-02-27 08:27:28 -05002439 return 0;
Joe Hershberger05622192011-10-18 10:06:59 +00002440}
2441sub WARN {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002442 my ($type, $msg) = @_;
2443
2444 if (report("WARNING", $type, $msg)) {
Joe Hershberger05622192011-10-18 10:06:59 +00002445 our $clean = 0;
2446 our $cnt_warn++;
Tom Rini6b9709d2014-02-27 08:27:28 -05002447 return 1;
Joe Hershberger05622192011-10-18 10:06:59 +00002448 }
Tom Rini6b9709d2014-02-27 08:27:28 -05002449 return 0;
Joe Hershberger05622192011-10-18 10:06:59 +00002450}
2451sub CHK {
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002452 my ($type, $msg) = @_;
2453
2454 if ($check && report("CHECK", $type, $msg)) {
Joe Hershberger05622192011-10-18 10:06:59 +00002455 our $clean = 0;
2456 our $cnt_chk++;
Tom Rini6b9709d2014-02-27 08:27:28 -05002457 return 1;
Joe Hershberger05622192011-10-18 10:06:59 +00002458 }
Tom Rini6b9709d2014-02-27 08:27:28 -05002459 return 0;
Joe Hershberger05622192011-10-18 10:06:59 +00002460}
2461
2462sub check_absolute_file {
2463 my ($absolute, $herecurr) = @_;
2464 my $file = $absolute;
2465
2466 ##print "absolute<$absolute>\n";
2467
2468 # See if any suffix of this path is a path within the tree.
2469 while ($file =~ s@^[^/]*/@@) {
2470 if (-f "$root/$file") {
2471 ##print "file<$file>\n";
2472 last;
2473 }
2474 }
2475 if (! -f _) {
2476 return 0;
2477 }
2478
2479 # It is, so see if the prefix is acceptable.
2480 my $prefix = $absolute;
2481 substr($prefix, -length($file)) = '';
2482
2483 ##print "prefix<$prefix>\n";
2484 if ($prefix ne ".../") {
2485 WARN("USE_RELATIVE_PATH",
2486 "use relative pathname instead of absolute in changelog text\n" . $herecurr);
2487 }
2488}
2489
Tom Rini6b9709d2014-02-27 08:27:28 -05002490sub trim {
2491 my ($string) = @_;
2492
2493 $string =~ s/^\s+|\s+$//g;
2494
2495 return $string;
2496}
2497
2498sub ltrim {
2499 my ($string) = @_;
2500
2501 $string =~ s/^\s+//;
2502
2503 return $string;
2504}
2505
2506sub rtrim {
2507 my ($string) = @_;
2508
2509 $string =~ s/\s+$//;
2510
2511 return $string;
2512}
2513
2514sub string_find_replace {
2515 my ($string, $find, $replace) = @_;
2516
2517 $string =~ s/$find/$replace/g;
2518
2519 return $string;
2520}
2521
2522sub tabify {
2523 my ($leading) = @_;
2524
Tom Rinic57383b2020-06-16 10:29:46 -04002525 my $source_indent = $tabsize;
Tom Rini6b9709d2014-02-27 08:27:28 -05002526 my $max_spaces_before_tab = $source_indent - 1;
2527 my $spaces_to_tab = " " x $source_indent;
2528
2529 #convert leading spaces to tabs
2530 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g;
2531 #Remove spaces before a tab
2532 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g;
2533
2534 return "$leading";
2535}
2536
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002537sub pos_last_openparen {
2538 my ($line) = @_;
2539
2540 my $pos = 0;
2541
2542 my $opens = $line =~ tr/\(/\(/;
2543 my $closes = $line =~ tr/\)/\)/;
2544
2545 my $last_openparen = 0;
2546
2547 if (($opens == 0) || ($closes >= $opens)) {
2548 return -1;
2549 }
2550
2551 my $len = length($line);
2552
2553 for ($pos = 0; $pos < $len; $pos++) {
2554 my $string = substr($line, $pos);
2555 if ($string =~ /^($FuncArg|$balanced_parens)/) {
2556 $pos += length($1) - 1;
2557 } elsif (substr($line, $pos, 1) eq '(') {
2558 $last_openparen = $pos;
2559 } elsif (index($string, '(') == -1) {
2560 last;
2561 }
2562 }
2563
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002564 return length(expand_tabs(substr($line, 0, $last_openparen))) + 1;
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002565}
2566
Tom Rinic57383b2020-06-16 10:29:46 -04002567sub get_raw_comment {
2568 my ($line, $rawline) = @_;
2569 my $comment = '';
2570
2571 for my $i (0 .. (length($line) - 1)) {
2572 if (substr($line, $i, 1) eq "$;") {
2573 $comment .= substr($rawline, $i, 1);
2574 }
2575 }
2576
2577 return $comment;
2578}
2579
Simon Glassb7bbd552020-12-03 16:55:24 -07002580# Args:
2581# line: Patch line to check
2582# auto: Auto variable name, e.g. "per_child_auto"
2583# suffix: Suffix to expect on member, e.g. "_priv"
2584# warning: Warning name, e.g. "PRIV_AUTO"
2585sub u_boot_struct_name {
Evan Bennec6db6c2021-04-01 13:49:30 +11002586 my ($line, $auto, $suffix, $warning, $herecurr) = @_;
Simon Glassb7bbd552020-12-03 16:55:24 -07002587
2588 # Use _priv as a suffix for the device-private data struct
2589 if ($line =~ /^\+\s*\.${auto}\s*=\s*sizeof\(struct\((\w+)\).*/) {
2590 my $struct_name = $1;
2591 if ($struct_name !~ /^\w+${suffix}/) {
Evan Bennec6db6c2021-04-01 13:49:30 +11002592 WARN($warning,
2593 "struct \'$struct_name\' should have a ${suffix} suffix\n"
2594 . $herecurr);
Simon Glassb7bbd552020-12-03 16:55:24 -07002595 }
2596 }
2597}
2598
Simon Glassb77df592020-05-22 16:32:36 -06002599# Checks specific to U-Boot
2600sub u_boot_line {
Simon Glass23552ba2020-07-19 10:16:01 -06002601 my ($realfile, $line, $rawline, $herecurr) = @_;
Simon Glass281236c2020-05-22 16:32:37 -06002602
2603 # ask for a test if a new uclass ID is added
2604 if ($realfile =~ /uclass-id.h/ && $line =~ /^\+/) {
2605 WARN("NEW_UCLASS",
2606 "Possible new uclass - make sure to add a sandbox driver, plus a test in test/dm/<name>.c\n" . $herecurr);
2607 }
Simon Glass7fc7d242020-05-22 16:32:38 -06002608
Lars Feyaerts814774c2023-10-02 10:00:13 +02002609 # try to get people to use the livetree API, except when changing tooling
2610 if ($line =~ /^\+.*fdtdec_/ && $realfile !~ /^tools\//) {
Simon Glass7fc7d242020-05-22 16:32:38 -06002611 WARN("LIVETREE",
2612 "Use the livetree API (dev_read_...)\n" . $herecurr);
2613 }
Simon Glass58978112020-05-22 16:32:39 -06002614
2615 # add tests for new commands
2616 if ($line =~ /^\+.*do_($Ident)\(struct cmd_tbl.*/) {
2617 WARN("CMD_TEST",
2618 "Possible new command - make sure you add a test\n" . $herecurr);
2619 }
Simon Glassdd5b0fa2020-05-22 16:32:40 -06002620
2621 # use if instead of #if
Simon Glass8af45b12020-06-14 10:54:08 -06002622 if ($realfile =~ /\.c$/ && $line =~ /^\+#if.*CONFIG.*/) {
Simon Glassdd5b0fa2020-05-22 16:32:40 -06002623 WARN("PREFER_IF",
2624 "Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible\n" . $herecurr);
2625 }
Tom Rinif3e2ebe2020-05-26 14:29:02 -04002626
Sean Andersond9c30502021-03-11 00:15:45 -05002627 # prefer strl(cpy|cat) over strn(cpy|cat)
2628 if ($line =~ /\bstrn(cpy|cat)\s*\(/) {
2629 WARN("STRL",
2630 "strl$1 is preferred over strn$1 because it always produces a nul-terminated string\n" . $herecurr);
2631 }
2632
Tom Rini2a06da02022-12-04 10:14:14 -05002633 # use Kconfig for all CONFIG symbols
2634 if ($line =~ /\+\s*#\s*(define|undef)\s+(CONFIG_\w*)\b/) {
2635 ERROR("DEFINE_CONFIG_SYM",
2636 "All CONFIG symbols are managed by Kconfig\n" . $herecurr);
Tom Rinif3e2ebe2020-05-26 14:29:02 -04002637 }
Simon Glass23552ba2020-07-19 10:16:01 -06002638
Tom Rinia8384f82023-10-13 09:28:32 -07002639 # Don't put dm.h in header files
2640 if ($realfile =~ /\.h$/ && $rawline =~ /^\+#include\s*<dm\.h>*/) {
Simon Glass23552ba2020-07-19 10:16:01 -06002641 ERROR("BARRED_INCLUDE_IN_HDR",
2642 "Avoid including common.h and dm.h in header files\n" . $herecurr);
2643 }
Tom Rini12178b52020-08-20 08:37:49 -04002644
Tom Rinia8384f82023-10-13 09:28:32 -07002645 # Don't add common.h to files
2646 if ($rawline =~ /^\+#include\s*<common\.h>*/) {
2647 ERROR("BARRED_INCLUDE_COMMON_H",
2648 "Do not add common.h to files\n" . $herecurr);
2649 }
2650
Tom Rini12178b52020-08-20 08:37:49 -04002651 # Do not disable fdt / initrd relocation
Hou Zhiqiang2f3e8d62021-12-15 14:23:52 +08002652 if ($rawline =~ /^\+.*(fdt|initrd)_high=0xffffffff/) {
Tom Rini12178b52020-08-20 08:37:49 -04002653 ERROR("DISABLE_FDT_OR_INITRD_RELOC",
2654 "fdt or initrd relocation disabled at boot time\n" . $herecurr);
2655 }
Alper Nebi Yasakb9cca2c2020-10-05 09:57:30 +03002656
Wasim Khan402558b2021-02-04 15:44:04 +01002657 # make sure 'skip_board_fixup' is not
2658 if ($rawline =~ /.*skip_board_fixup.*/) {
2659 ERROR("SKIP_BOARD_FIXUP",
2660 "Avoid setting skip_board_fixup env variable\n" . $herecurr);
2661 }
2662
Alper Nebi Yasakb9cca2c2020-10-05 09:57:30 +03002663 # Do not use CONFIG_ prefix in CONFIG_IS_ENABLED() calls
2664 if ($line =~ /^\+.*CONFIG_IS_ENABLED\(CONFIG_\w*\).*/) {
2665 ERROR("CONFIG_IS_ENABLED_CONFIG",
2666 "CONFIG_IS_ENABLED() takes values without the CONFIG_ prefix\n" . $herecurr);
2667 }
Simon Glassb7bbd552020-12-03 16:55:24 -07002668
2669 # Use _priv as a suffix for the device-private data struct
2670 if ($line =~ /^\+\s*\.priv_auto\s*=\s*sizeof\(struct\((\w+)\).*/) {
2671 my $struct_name = $1;
2672 if ($struct_name !~ /^\w+_priv/) {
2673 WARN("PRIV_AUTO", "struct \'$struct_name\' should have a _priv suffix");
2674 }
2675 }
2676
2677 # Check struct names for the 'auto' members of struct driver
Evan Bennec6db6c2021-04-01 13:49:30 +11002678 u_boot_struct_name($line, "priv_auto", "_priv", "PRIV_AUTO", $herecurr);
2679 u_boot_struct_name($line, "plat_auto", "_plat", "PLAT_AUTO", $herecurr);
2680 u_boot_struct_name($line, "per_child_auto", "_priv", "CHILD_PRIV_AUTO", $herecurr);
Simon Glassb7bbd552020-12-03 16:55:24 -07002681 u_boot_struct_name($line, "per_child_plat_auto", "_plat",
Evan Bennec6db6c2021-04-01 13:49:30 +11002682 "CHILD_PLAT_AUTO", $herecurr);
Simon Glassb7bbd552020-12-03 16:55:24 -07002683
2684 # Now the ones for struct uclass, skipping those in common with above
2685 u_boot_struct_name($line, "per_device_auto", "_priv",
Evan Bennec6db6c2021-04-01 13:49:30 +11002686 "DEVICE_PRIV_AUTO", $herecurr);
Simon Glassb7bbd552020-12-03 16:55:24 -07002687 u_boot_struct_name($line, "per_device_plat_auto", "_plat",
Evan Bennec6db6c2021-04-01 13:49:30 +11002688 "DEVICE_PLAT_AUTO", $herecurr);
Simon Glass48be5462023-02-13 08:56:38 -07002689
2690 # Avoid using the pre-schema driver model tags
2691 if ($line =~ /^\+.*u-boot,dm-.*/) {
2692 ERROR("PRE_SCHEMA",
2693 "Driver model schema uses 'bootph-...' tags now\n" . $herecurr);
2694 }
Simon Glassb77df592020-05-22 16:32:36 -06002695}
2696
Tom Rinie199fb32021-08-03 08:31:56 -04002697sub exclude_global_initialisers {
2698 my ($realfile) = @_;
2699
2700 # Do not check for BPF programs (tools/testing/selftests/bpf/progs/*.c, samples/bpf/*_kern.c, *.bpf.c).
2701 return $realfile =~ m@^tools/testing/selftests/bpf/progs/.*\.c$@ ||
2702 $realfile =~ m@^samples/bpf/.*_kern\.c$@ ||
2703 $realfile =~ m@/bpf/.*\.bpf\.c$@;
2704}
2705
Joe Hershberger05622192011-10-18 10:06:59 +00002706sub process {
2707 my $filename = shift;
2708
2709 my $linenr=0;
2710 my $prevline="";
2711 my $prevrawline="";
2712 my $stashline="";
2713 my $stashrawline="";
2714
2715 my $length;
2716 my $indent;
2717 my $previndent=0;
2718 my $stashindent=0;
2719
2720 our $clean = 1;
2721 my $signoff = 0;
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02002722 my $author = '';
2723 my $authorsignoff = 0;
Tom Rinie199fb32021-08-03 08:31:56 -04002724 my $author_sob = '';
Joe Hershberger05622192011-10-18 10:06:59 +00002725 my $is_patch = 0;
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02002726 my $is_binding_patch = -1;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002727 my $in_header_lines = $file ? 0 : 1;
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002728 my $in_commit_log = 0; #Scanning lines before patch
Tom Rinic57383b2020-06-16 10:29:46 -04002729 my $has_patch_separator = 0; #Found a --- line
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002730 my $has_commit_log = 0; #Encountered lines before patch
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02002731 my $commit_log_lines = 0; #Number of commit log lines
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002732 my $commit_log_possible_stack_dump = 0;
2733 my $commit_log_long_line = 0;
2734 my $commit_log_has_diff = 0;
2735 my $reported_maintainer_file = 0;
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002736 my $non_utf8_charset = 0;
2737
Simon Glass587254e2022-01-23 12:55:11 -07002738 my $last_git_commit_id_linenr = -1;
2739
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002740 my $last_blank_line = 0;
2741 my $last_coalesced_string_linenr = -1;
2742
Joe Hershberger05622192011-10-18 10:06:59 +00002743 our @report = ();
2744 our $cnt_lines = 0;
2745 our $cnt_error = 0;
2746 our $cnt_warn = 0;
2747 our $cnt_chk = 0;
2748
2749 # Trace the real file/line as we go.
2750 my $realfile = '';
2751 my $realline = 0;
2752 my $realcnt = 0;
2753 my $here = '';
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002754 my $context_function; #undef'd unless there's a known function
Joe Hershberger05622192011-10-18 10:06:59 +00002755 my $in_comment = 0;
2756 my $comment_edge = 0;
2757 my $first_line = 0;
2758 my $p1_prefix = '';
2759
2760 my $prev_values = 'E';
2761
2762 # suppression flags
2763 my %suppress_ifbraces;
2764 my %suppress_whiletrailers;
2765 my %suppress_export;
Kim Phillipsd45a6ae2013-02-28 12:53:52 +00002766 my $suppress_statement = 0;
2767
Tom Rini6b9709d2014-02-27 08:27:28 -05002768 my %signatures = ();
Joe Hershberger05622192011-10-18 10:06:59 +00002769
2770 # Pre-scan the patch sanitizing the lines.
2771 # Pre-scan the patch looking for any __setup documentation.
2772 #
2773 my @setup_docs = ();
2774 my $setup_docs = 0;
2775
Tom Rini6b9709d2014-02-27 08:27:28 -05002776 my $camelcase_file_seeded = 0;
2777
Heinrich Schuchardtc398f2d2018-04-04 15:39:20 +02002778 my $checklicenseline = 1;
2779
Joe Hershberger05622192011-10-18 10:06:59 +00002780 sanitise_line_reset();
2781 my $line;
2782 foreach my $rawline (@rawlines) {
2783 $linenr++;
2784 $line = $rawline;
2785
Tom Rini6b9709d2014-02-27 08:27:28 -05002786 push(@fixed, $rawline) if ($fix);
2787
Joe Hershberger05622192011-10-18 10:06:59 +00002788 if ($rawline=~/^\+\+\+\s+(\S+)/) {
2789 $setup_docs = 0;
Tom Rinie199fb32021-08-03 08:31:56 -04002790 if ($1 =~ m@Documentation/admin-guide/kernel-parameters.txt$@) {
Joe Hershberger05622192011-10-18 10:06:59 +00002791 $setup_docs = 1;
2792 }
2793 #next;
2794 }
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002795 if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
Joe Hershberger05622192011-10-18 10:06:59 +00002796 $realline=$1-1;
2797 if (defined $2) {
2798 $realcnt=$3+1;
2799 } else {
2800 $realcnt=1+1;
2801 }
2802 $in_comment = 0;
2803
2804 # Guestimate if this is a continuing comment. Run
2805 # the context looking for a comment "edge". If this
2806 # edge is a close comment then we must be in a comment
2807 # at context start.
2808 my $edge;
2809 my $cnt = $realcnt;
2810 for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
2811 next if (defined $rawlines[$ln - 1] &&
2812 $rawlines[$ln - 1] =~ /^-/);
2813 $cnt--;
2814 #print "RAW<$rawlines[$ln - 1]>\n";
2815 last if (!defined $rawlines[$ln - 1]);
2816 if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
2817 $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
2818 ($edge) = $1;
2819 last;
2820 }
2821 }
2822 if (defined $edge && $edge eq '*/') {
2823 $in_comment = 1;
2824 }
2825
2826 # Guestimate if this is a continuing comment. If this
2827 # is the start of a diff block and this line starts
2828 # ' *' then it is very likely a comment.
2829 if (!defined $edge &&
2830 $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
2831 {
2832 $in_comment = 1;
2833 }
2834
2835 ##print "COMMENT:$in_comment edge<$edge> $rawline\n";
2836 sanitise_line_reset($in_comment);
2837
2838 } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
2839 # Standardise the strings and chars within the input to
2840 # simplify matching -- only bother with positive lines.
2841 $line = sanitise_line($rawline);
2842 }
2843 push(@lines, $line);
2844
2845 if ($realcnt > 1) {
2846 $realcnt-- if ($line =~ /^(?:\+| |$)/);
2847 } else {
2848 $realcnt = 0;
2849 }
2850
2851 #print "==>$rawline\n";
2852 #print "-->$line\n";
2853
2854 if ($setup_docs && $line =~ /^\+/) {
2855 push(@setup_docs, $line);
2856 }
2857 }
2858
2859 $prefix = '';
2860
2861 $realcnt = 0;
2862 $linenr = 0;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002863 $fixlinenr = -1;
Joe Hershberger05622192011-10-18 10:06:59 +00002864 foreach my $line (@lines) {
2865 $linenr++;
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002866 $fixlinenr++;
Tom Rini6b9709d2014-02-27 08:27:28 -05002867 my $sline = $line; #copy of $line
2868 $sline =~ s/$;/ /g; #with comments as spaces
Joe Hershberger05622192011-10-18 10:06:59 +00002869
2870 my $rawline = $rawlines[$linenr - 1];
Tom Rinic57383b2020-06-16 10:29:46 -04002871 my $raw_comment = get_raw_comment($line, $rawline);
Joe Hershberger05622192011-10-18 10:06:59 +00002872
Heinrich Schuchardtc261fef2019-10-19 09:06:38 +02002873# check if it's a mode change, rename or start of a patch
2874 if (!$in_commit_log &&
2875 ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ ||
2876 ($line =~ /^rename (?:from|to) \S+\s*$/ ||
2877 $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) {
2878 $is_patch = 1;
2879 }
2880
Joe Hershberger05622192011-10-18 10:06:59 +00002881#extract the line range in the file after the patch is applied
Heinrich Schuchardt6305db92017-09-12 09:57:45 +02002882 if (!$in_commit_log &&
2883 $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
2884 my $context = $4;
Joe Hershberger05622192011-10-18 10:06:59 +00002885 $is_patch = 1;
2886 $first_line = $linenr + 1;
2887 $realline=$1-1;
2888 if (defined $2) {
2889 $realcnt=$3+1;
2890 } else {
2891 $realcnt=1+1;
2892 }
2893 annotate_reset();
2894 $prev_values = 'E';
2895
2896 %suppress_ifbraces = ();
2897 %suppress_whiletrailers = ();
2898 %suppress_export = ();
Kim Phillipsd45a6ae2013-02-28 12:53:52 +0000289