Newer
Older
# SPDX-License-Identifier: GPL-2.0
#
# (c) 2001, Dave Jones. (the file handling bit)
# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
# (c) 2010-2018 Joe Perches <joe@perches.com>
use File::Basename;
use Cwd 'abs_path';
use Term::ANSIColor qw(:constants);
use Encode qw(decode encode);
my $D = dirname(abs_path($P));
use Getopt::Long qw(:config no_auto_abbrev);
my $quiet = 0;
my $tree = 1;
my $chk_signoff = 1;
my $chk_patch = 1;
my $showfile = 0;
my %git_commits = ();
my $check_orig = 0;
my $summary = 1;
my $mailback = 0;
my $list_types = 0;
my $fix = 0;
my %camelcase = ();
my %use_type = ();
my @use = ();
my %ignore_type = ();
my $help = 0;
my $configuration_file = ".checkpatch.conf";
my $max_line_length = 80;
my $ignore_perl_version = 0;
my $minimum_perl_version = 5.10.0;
my $min_conf_desc_length = 4;
my $spelling_file = "$D/spelling.txt";
my $codespell = 0;
my $codespellfile = "/usr/share/codespell/dictionary.txt";
my $conststructsfile = "$D/const_structs.checkpatch";
my $color = "auto";
my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE
sub help {
my ($exitcode) = @_;
print << "EOM";
Usage: $P [OPTION]... [FILE]...
Version: $V
Options:
-q, --quiet quiet
--no-tree run without a kernel tree
--no-signoff do not check for 'Signed-off-by' line
--patch treat FILE as patchfile (default)
--emacs emacs compile window format
--terse one line per report
--showfile emit diffed file position, not input file position
-g, --git treat FILE as a single commit or git revision range
single git commit with:
<rev>
<rev>^
<rev>~n
multiple git commits with:
<rev1>..<rev2>
<rev1>...<rev2>
<rev>-<count>
git merges are ignored
-f, --file treat FILE as regular source file
--subjective, --strict enable more subjective tests
--list-types list the possible message types
--types TYPE(,TYPE2...) show only these comma separated message types
--ignore TYPE(,TYPE2...) ignore various comma separated message types
--show-types show the specific message type in the output
--max-line-length=n set the maximum line length, if exceeded, warn
--min-conf-desc-length=n set the min description length, if shorter, warn
--root=PATH PATH to the kernel tree root
--no-summary suppress the per-file summary
--mailback only produce a report in case of warnings/errors
--summary-file include the filename in summary
--debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of
'values', 'possible', 'type', and 'attr' (default
is all off)
--test-only=WORD report only warnings/errors containing WORD
literally
--fix EXPERIMENTAL - may create horrible results
If correctable single-line errors exist, create
"<inputfile>.EXPERIMENTAL-checkpatch-fixes"
with potential errors corrected to the preferred
checkpatch style
--fix-inplace EXPERIMENTAL - may create horrible results
Is the same as --fix, but overwrites the input
file. It's your fault if there's no backup or git
--ignore-perl-version override checking of perl version. expect
runtime errors.
--codespell Use the codespell dictionary for spelling/typos
(default:/usr/share/codespell/dictionary.txt)
--codespellfile Use this codespell dictionary
--typedefsfile Read additional types from this file
--color[=WHEN] Use colors 'always', 'never', or only when output
is a terminal ('auto'). Default is 'auto'.
-h, --help, --version display this help and exit
When FILE is - read standard input.
EOM
exit($exitcode);
}
sub uniq {
my %seen;
return grep { !$seen{$_}++ } @_;
}
sub list_types {
my ($exitcode) = @_;
my $count = 0;
local $/ = undef;
open(my $script, '<', abs_path($P)) or
die "$P: Can't read '$P' $!\n";
my $text = <$script>;
close($script);
my @types = ();
# Also catch when type or level is passed through a variable
for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
push (@types, $_);
}
@types = sort(uniq(@types));
print("#\tMessage type\n\n");
foreach my $type (@types) {
print(++$count . "\t" . $type . "\n");
}
exit($exitcode);
}
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
my $conf = which_conf($configuration_file);
if (-f $conf) {
my @conf_args;
open(my $conffile, '<', "$conf")
or warn "$P: Can't find a readable $configuration_file file $!\n";
while (<$conffile>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
$line =~ s/\s+/ /g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
my @words = split(" ", $line);
foreach my $word (@words) {
last if ($word =~ m/^#/);
push (@conf_args, $word);
}
}
close($conffile);
unshift(@ARGV, @conf_args) if @conf_args;
}
# Perl's Getopt::Long allows options to take optional arguments after a space.
# Prevent --color by itself from consuming other arguments
foreach (@ARGV) {
if ($_ eq "--color" || $_ eq "-color") {
$_ = "--color=$color";
}
}
'tree!' => \$tree,
'signoff!' => \$chk_signoff,
'patch!' => \$chk_patch,
'showfile!' => \$showfile,
'f|file!' => \$file,
'g|git!' => \$git,
'subjective!' => \$check,
'strict!' => \$check,
'ignore=s' => \@ignore,
'types=s' => \@use,
'show-types!' => \$show_types,
'list-types!' => \$list_types,
'max-line-length=i' => \$max_line_length,
'min-conf-desc-length=i' => \$min_conf_desc_length,
'summary!' => \$summary,
'mailback!' => \$mailback,
'summary-file!' => \$summary_file,
'fix!' => \$fix,
'ignore-perl-version!' => \$ignore_perl_version,
'codespell!' => \$codespell,
'codespellfile=s' => \$codespellfile,
'color=s' => \$color,
'no-color' => \$color, #keep old behaviors of -nocolor
'nocolor' => \$color, #keep old behaviors of -nocolor
'h|help' => \$help,
'version' => \$help
) or help(1);
help(0) if ($help);
list_types(0) if ($list_types);
$check_orig = $check;
my $perl_version_ok = 1;
if ($^V && $^V lt $minimum_perl_version) {
$perl_version_ok = 0;
printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
exit(1) if (!$ignore_perl_version);
#if no filenames are given, push '-' to read patch from stdin
if ($color =~ /^[01]$/) {
$color = !$color;
} elsif ($color =~ /^always$/i) {
$color = 1;
} elsif ($color =~ /^never$/i) {
$color = 0;
} elsif ($color =~ /^auto$/i) {
$color = (-t STDOUT);
} else {
die "Invalid color mode: $color\n";
}
sub hash_save_array_words {
my ($hashRef, $arrayRef) = @_;
my @array = split(/,/, join(',', @$arrayRef));
foreach my $word (@array) {
$word =~ s/\s*\n?$//g;
$word =~ s/^\s*//g;
$word =~ s/\s+/ /g;
$word =~ tr/[a-z]/[A-Z]/;
next if ($word =~ m/^\s*#/);
next if ($word =~ m/^\s*$/);
$hashRef->{$word}++;
}
}
sub hash_show_words {
my ($hashRef, $prefix) = @_;
if (keys %$hashRef) {
print "\nNOTE: $prefix message types:";
foreach my $word (sort keys %$hashRef) {
print " $word";
}
hash_save_array_words(\%ignore_type, \@ignore);
hash_save_array_words(\%use_type, \@use);
my $dbg_values = 0;
my $dbg_possible = 0;
## no critic
eval "\${dbg_$key} = '$debug{$key}';";
die "$@" if ($@);
my $rpt_cleaners = 0;
if ($terse) {
$emacs = 1;
$quiet++;
}
if ($tree) {
if (defined $root) {
if (!top_of_kernel_tree($root)) {
die "$P: $root: --root does not point at a valid tree\n";
}
} else {
if (top_of_kernel_tree('.')) {
$root = '.';
} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
top_of_kernel_tree($1)) {
$root = $1;
}
}
if (!defined $root) {
print "Must be run from the top-level dir. of a kernel tree\n";
exit(2);
}
our $Ident = qr{
[A-Za-z_][A-Za-z\d_]*
(?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
}x;
our $Storage = qr{extern|static|asmlinkage};
our $Sparse = qr{
__user|
__kernel|
__force|
__iomem|
__must_check|
our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)};
our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)};
our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)};
our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)};
our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit};
Joe Perches
committed
# Notes to $Attribute:
# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
__percpu|
__nocast|
__safe|
__packed__|
__packed2__|
__naked|
__maybe_unused|
__always_unused|
__noreturn|
__used|
__cold|
__noclone|
__deprecated|
Joe Perches
committed
$InitAttribute|
____cacheline_aligned|
____cacheline_aligned_in_smp|
____cacheline_internodealigned_in_smp|
__weak
Joe Perches
committed
our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__};
our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
our $Lval = qr{$Ident(?:$Member)*};
our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u};
our $Binary = qr{(?i)0b[01]+$Int_type?};
our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?};
our $Int = qr{[0-9]+$Int_type?};
our $Octal = qr{0[0-7]+$Int_type?};
our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
our $Float = qr{$Float_hex|$Float_dec|$Float_int};
our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int};
our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
our $Compare = qr{<=|>=|==|!=|<|(?<!-)>};
our $Arithmetic = qr{\+|-|\*|\/|%};
our $Operators = qr{
<=|>=|==|!=|
=>|->|<<|>>|<|>|!|~|
&&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
Joe Perches
committed
our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x;
our $NonptrTypeMisordered;
Joe Perches
committed
our $NonptrTypeWithAttr;
our $TypeMisordered;
our $DeclareMisordered;
our $NON_ASCII_UTF8 = qr{
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
}x;
our $UTF8 = qr{
[\x09\x0A\x0D\x20-\x7E] # ASCII
| $NON_ASCII_UTF8
}x;
our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t};
our $typeOtherOSTypedefs = qr{(?x:
u_(?:char|short|int|long) | # bsd
u(?:nchar|short|int|long) # sysv
)};
our $typeKernelTypedefs = qr{(?x:
(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
our $typeTypedefs = qr{(?x:
$typeC99Typedefs\b|
$typeOtherOSTypedefs\b|
$typeKernelTypedefs\b
)};
our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
our $logFunctions = qr{(?x:
printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
(?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
panic|
MODULE_[A-Z_]+|
seq_vprintf|seq_printf|seq_puts
)};
our $allocFunctions = qr{(?x:
(?:(?:devm_)?
(?:kv|k|v)[czm]alloc(?:_node|_array)? |
kstrdup(?:_const)? |
kmemdup(?:_nul)?) |
(?:\w+)?alloc_skb(?:ip_align)? |
# dev_alloc_skb/netdev_alloc_skb, et al
dma_alloc_coherent
)};
our $signature_tags = qr{(?xi:
Signed-off-by:|
Co-developed-by:|
Acked-by:|
Tested-by:|
Reviewed-by:|
Reported-by:|
To:|
Cc:
)};
our @typeListMisordered = (
qr{char\s+(?:un)?signed},
qr{int\s+(?:(?:un)?signed\s+)?short\s},
qr{int\s+short(?:\s+(?:un)?signed)},
qr{short\s+int(?:\s+(?:un)?signed)},
qr{(?:un)?signed\s+int\s+short},
qr{short\s+(?:un)?signed},
qr{long\s+int\s+(?:un)?signed},
qr{int\s+long\s+(?:un)?signed},
qr{long\s+(?:un)?signed\s+int},
qr{int\s+(?:un)?signed\s+long},
qr{int\s+(?:un)?signed},
qr{int\s+long\s+long\s+(?:un)?signed},
qr{long\s+long\s+int\s+(?:un)?signed},
qr{long\s+long\s+(?:un)?signed\s+int},
qr{long\s+long\s+(?:un)?signed},
qr{long\s+(?:un)?signed},
);
qr{(?:(?:un)?signed\s+)?char},
qr{(?:(?:un)?signed\s+)?short\s+int},
qr{(?:(?:un)?signed\s+)?short},
qr{(?:(?:un)?signed\s+)?int},
qr{(?:(?:un)?signed\s+)?long\s+int},
qr{(?:(?:un)?signed\s+)?long\s+long\s+int},
qr{(?:(?:un)?signed\s+)?long\s+long},
qr{(?:(?:un)?signed\s+)?long},
qr{(?:un)?signed},
qr{float},
qr{double},
qr{bool},
qr{struct\s+$Ident},
qr{union\s+$Ident},
qr{enum\s+$Ident},
qr{${Ident}_t},
qr{${Ident}_handler},
qr{${Ident}_handler_fn},
@typeListMisordered,
our $C90_int_types = qr{(?x:
long\s+long\s+int\s+(?:un)?signed|
long\s+long\s+(?:un)?signed\s+int|
long\s+long\s+(?:un)?signed|
(?:(?:un)?signed\s+)?long\s+long\s+int|
(?:(?:un)?signed\s+)?long\s+long|
int\s+long\s+long\s+(?:un)?signed|
int\s+(?:(?:un)?signed\s+)?long\s+long|
long\s+int\s+(?:un)?signed|
long\s+(?:un)?signed\s+int|
long\s+(?:un)?signed|
(?:(?:un)?signed\s+)?long\s+int|
(?:(?:un)?signed\s+)?long|
int\s+long\s+(?:un)?signed|
int\s+(?:(?:un)?signed\s+)?long|
int\s+(?:un)?signed|
(?:(?:un)?signed\s+)?int
)};
our @typeListFile = ();
Joe Perches
committed
our @typeListWithAttr = (
@typeList,
qr{struct\s+$InitAttribute\s+$Ident},
qr{union\s+$InitAttribute\s+$Ident},
);
our @modifierList = (
qr{fastcall},
);
our @modifierListFile = ();
our @mode_permission_funcs = (
["module_param", 3],
["module_param_(?:array|named|string)", 4],
["module_param_array_named", 5],
["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2],
["proc_create(?:_data|)", 2],
["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2],
["IIO_DEV_ATTR_[A-Z_]+", 1],
["SENSOR_(?:DEVICE_|)ATTR_2", 2],
["SENSOR_TEMPLATE(?:_2|)", 3],
["__ATTR", 2],
#Create a search pattern for all these functions to speed up a loop below
our $mode_perms_search = "";
foreach my $entry (@mode_permission_funcs) {
$mode_perms_search .= '|' if ($mode_perms_search ne "");
$mode_perms_search .= $entry->[0];
}
$mode_perms_search = "(?:${mode_perms_search})";
our %deprecated_apis = (
"synchronize_rcu_bh" => "synchronize_rcu",
"synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited",
"call_rcu_bh" => "call_rcu",
"rcu_barrier_bh" => "rcu_barrier",
"synchronize_sched" => "synchronize_rcu",
"synchronize_sched_expedited" => "synchronize_rcu_expedited",
"call_rcu_sched" => "call_rcu",
"rcu_barrier_sched" => "rcu_barrier",
"get_state_synchronize_sched" => "get_state_synchronize_rcu",
"cond_synchronize_sched" => "cond_synchronize_rcu",
);
#Create a search pattern for all these strings to speed up a loop below
our $deprecated_apis_search = "";
foreach my $entry (keys %deprecated_apis) {
$deprecated_apis_search .= '|' if ($deprecated_apis_search ne "");
$deprecated_apis_search .= $entry;
}
$deprecated_apis_search = "(?:${deprecated_apis_search})";
our $mode_perms_world_writable = qr{
S_IWUGO |
S_IWOTH |
S_IRWXUGO |
S_IALLUGO |
0[0-7][0-7][2367]
}x;
our %mode_permission_string_types = (
"S_IRWXU" => 0700,
"S_IRUSR" => 0400,
"S_IWUSR" => 0200,
"S_IXUSR" => 0100,
"S_IRWXG" => 0070,
"S_IRGRP" => 0040,
"S_IWGRP" => 0020,
"S_IXGRP" => 0010,
"S_IRWXO" => 0007,
"S_IROTH" => 0004,
"S_IWOTH" => 0002,
"S_IXOTH" => 0001,
"S_IRWXUGO" => 0777,
"S_IRUGO" => 0444,
"S_IWUGO" => 0222,
"S_IXUGO" => 0111,
);
#Create a search pattern for all these strings to speed up a loop below
our $mode_perms_string_search = "";
foreach my $entry (keys %mode_permission_string_types) {
$mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
$mode_perms_string_search .= $entry;
}
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
our $single_mode_perms_string_search = "(?:${mode_perms_string_search})";
our $multi_mode_perms_string_search = qr{
${single_mode_perms_string_search}
(?:\s*\|\s*${single_mode_perms_string_search})*
}x;
sub perms_to_octal {
my ($string) = @_;
return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/);
my $val = "";
my $oval = "";
my $to = 0;
my $curpos = 0;
my $lastpos = 0;
while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
$curpos = pos($string);
my $match = $2;
my $omatch = $1;
last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
$lastpos = $curpos;
$to |= $mode_permission_string_types{$match};
$val .= '\s*\|\s*' if ($val ne "");
$val .= $match;
$oval .= $omatch;
}
$oval =~ s/^\s*\|\s*//;
$oval =~ s/\s*\|\s*$//;
return sprintf("%04o", $to);
}
our $allowed_asm_includes = qr{(?x:
irq|
memory|
time|
reboot
)};
# memory.h: ARM has a custom one
# Load common spelling mistakes and build regular expression list.
my $misspellings;
my %spelling_fix;
if (open(my $spelling, '<', $spelling_file)) {
while (<$spelling>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
my ($suspect, $fix) = split(/\|\|/, $line);
$spelling_fix{$suspect} = $fix;
}
close($spelling);
} else {
warn "No typos will be found - file '$spelling_file': $!\n";
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
if ($codespell) {
if (open(my $spelling, '<', $codespellfile)) {
while (<$spelling>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
next if ($line =~ m/, disabled/i);
$line =~ s/,.*$//;
my ($suspect, $fix) = split(/->/, $line);
$spelling_fix{$suspect} = $fix;
}
close($spelling);
} else {
warn "No codespell typos will be found - file '$codespellfile': $!\n";
}
}
$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix;
sub read_words {
my ($wordsRef, $file) = @_;
if (open(my $words, '<', $file)) {
while (<$words>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
if ($line =~ /\s/) {
print("$file: '$line' invalid - ignored\n");
next;
}
$$wordsRef .= '|' if ($$wordsRef ne "");
$$wordsRef .= $line;
}
close($file);
return 1;
return 0;
}
my $const_structs = "";
read_words(\$const_structs, $conststructsfile)
or warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
my $typeOtherTypedefs = "";
if (length($typedefsfile)) {
read_words(\$typeOtherTypedefs, $typedefsfile)
or warn "No additional types will be considered - file '$typedefsfile': $!\n";
$typeTypedefs .= '|' . $typeOtherTypedefs if ($typeOtherTypedefs ne "");
my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)";
my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)";
my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)";
Joe Perches
committed
my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)";
$Modifier = qr{(?:$Attribute|$Sparse|$mods)};
$BasicType = qr{
(?:$typeTypedefs\b)|
(?:${all}\b)
}x;
(?:$Modifier\s+|const\s+)*
(?:typeof|__typeof__)\s*\([^\)]*\)|
(?:\s+$Modifier|\s+const)*
$NonptrTypeMisordered = qr{
(?:$Modifier\s+|const\s+)*
(?:
(?:${Misordered}\b)
)
(?:\s+$Modifier|\s+const)*
}x;
Joe Perches
committed
$NonptrTypeWithAttr = qr{
(?:$Modifier\s+|const\s+)*
(?:
(?:typeof|__typeof__)\s*\([^\)]*\)|
(?:$typeTypedefs\b)|
(?:${allWithAttr}\b)
)
(?:\s+$Modifier|\s+const)*
}x;
(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)?
(?:\s+$Inline|\s+$Modifier)*
$TypeMisordered = qr{
$NonptrTypeMisordered
(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)?
(?:\s+$Inline|\s+$Modifier)*
}x;
Joe Perches
committed
$Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type};
$DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered};
our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
# Using $balanced_parens, $LvalOrFunc, or $FuncArg
# requires at least perl version v5.10.0
# Any use must be runtime checked with $^V
our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*};
our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
our $declaration_macros = qr{(?x:
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
(?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(|
(?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
sub deparenthesize {
my ($string) = @_;
return "" if (!defined($string));
while ($string =~ /^\s*\(.*\)\s*$/) {
$string =~ s@^\s*\(\s*@@;
$string =~ s@\s*\)\s*$@@;
}
sub seed_camelcase_file {
my ($file) = @_;
return if (!(-f $file));
local $/;
open(my $include_file, '<', "$file")
or warn "$P: Can't read '$file' $!\n";
my $text = <$include_file>;
close($include_file);
my @lines = split('\n', $text);
foreach my $line (@lines) {
next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/);
if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) {
$camelcase{$1} = 1;
} elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) {
$camelcase{$1} = 1;
} elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) {
$camelcase{$1} = 1;
}
}
}
sub is_maintained_obsolete {
my ($filename) = @_;
return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl"));
my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
return $status =~ /obsolete/i;
}
sub is_SPDX_License_valid {
my ($license) = @_;
return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git"));
my $root_path = abs_path($root);
my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
return 0 if ($status ne "");
return 1;
}
my $camelcase_seeded = 0;
sub seed_camelcase_includes {
return if ($camelcase_seeded);
my $files;
my $camelcase_cache = "";
my @include_files = ();
$camelcase_seeded = 1;
my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`;
chomp $git_last_include_commit;
$camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
my $last_mod_date = 0;
$files = `find $root/include -name "*.h"`;
@include_files = split('\n', $files);
foreach my $file (@include_files) {
my $date = POSIX::strftime("%Y%m%d%H%M",
localtime((stat $file)[9]));
$last_mod_date = $date if ($last_mod_date < $date);
}
$camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date";
}
if ($camelcase_cache ne "" && -f $camelcase_cache) {
open(my $camelcase_file, '<', "$camelcase_cache")
or warn "$P: Can't read '$camelcase_cache' $!\n";
while (<$camelcase_file>) {
chomp;
$camelcase{$_} = 1;
}
close($camelcase_file);
return;
$files = `git ls-files "include/*.h"`;
@include_files = split('\n', $files);
}
foreach my $file (@include_files) {
seed_camelcase_file($file);
}
if ($camelcase_cache ne "") {
unlink glob ".checkpatch-camelcase.*";
open(my $camelcase_file, '>', "$camelcase_cache")
or warn "$P: Can't write '$camelcase_cache' $!\n";
foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) {
print $camelcase_file ("$_\n");
}
close($camelcase_file);
}
sub git_commit_info {
my ($commit, $id, $desc) = @_;
return ($id, $desc) if ((which("git") eq "") || !(-e ".git"));
my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`;
$output =~ s/^\s*//gm;
my @lines = split("\n", $output);
return ($id, $desc) if ($#lines < 0);
if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) {
# Maybe one day convert this block of bash into something that returns
# all matching commit ids, but it's very slow...
#
# echo "checking commits $1..."
# git rev-list --remotes | grep -i "^$1" |
# while read line ; do
# git log --format='%H %s' -1 $line |
# echo "commit $(cut -c 1-12,41-)"
# done
} elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) {
$id = undef;
} else {
$id = substr($lines[0], 0, 12);
$desc = substr($lines[0], 41);
}
return ($id, $desc);
}
my @fixed = ();
my @fixed_inserted = ();
my @fixed_deleted = ();
# If input is git commits, extract all commits from the commit expressions.
# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'.
die "$P: No git repository found\n" if ($git && !-e ".git");
if ($git) {
my @commits = ();
foreach my $commit_expr (@ARGV) {