2014-06-25 21:22:49 -07:00
#!/usr/bin/perl -w
# (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) 2014 Gluster Community <gluster-devel@gluster.org>
# Licensed under the terms of the GNU GPL License version 2
use strict ;
use POSIX ;
my $ P = $ 0 ;
$ P =~ s@.*/@@g ;
my $ V = '0.32.1' ;
use Getopt::Long qw( :config no_auto_abbrev ) ;
my $ quiet = 0 ;
my $ tree = 1 ;
my $ chk_signoff = 1 ;
my $ chk_patch = 1 ;
my $ tst_only ;
my $ emacs = 0 ;
my $ terse = 0 ;
my $ file = 0 ;
my $ check = 0 ;
my $ check_orig = 0 ;
my $ summary = 1 ;
my $ mailback = 0 ;
my $ summary_file = 0 ;
my $ show_types = 0 ;
my $ fix = 0 ;
my $ fix_inplace = 0 ;
my $ root ;
my % debug ;
my % camelcase = ( ) ;
my % use_type = ( ) ;
my @ use = ( ) ;
my % ignore_type = ( ) ;
my @ ignore = ( ) ;
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 ;
2015-04-12 16:23:55 +01:00
my $ gerrit_url = $ ENV { GERRIT_URL } ;
2014-06-25 21:22:49 -07:00
sub help {
my ( $ exitcode ) = @ _ ;
print << "EOM" ;
Usage: $ P [ OPTION ] ... [ FILE ] ...
Version: $ V
Options:
- q , - - quiet quiet
- - patch treat FILE as patchfile ( default )
- - emacs emacs compile window format
2015-04-12 16:23:55 +01:00
- - gerrit - url = STRING URL the patch was reviewed at
2014-06-25 21:22:49 -07:00
- - terse one line per report
- f , - - file treat FILE as regular source file
- - subjective , - - strict enable more subjective tests
- - types TYPE ( , TYPE2 ... ) show only these comma separated message types
- - ignore TYPE ( , TYPE2 ... ) ignore various comma separated message types
- - max - line - length = n set the maximum line length , if exceeded , warn
- - show - types show the message "types" in the output
- - root = PATH PATH to the glusterfs 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 .
- h , - - help , - - version display this help and exit
When FILE is - read standard input .
EOM
exit ( $ exitcode ) ;
}
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 ;
}
GetOptions (
'q|quiet+' = > \ $ quiet ,
'patch!' = > \ $ chk_patch ,
'emacs!' = > \ $ emacs ,
2015-04-12 16:23:55 +01:00
'gerrit-url=s' = > \ $ gerrit_url ,
2014-06-25 21:22:49 -07:00
'terse!' = > \ $ terse ,
'f|file!' = > \ $ file ,
'subjective!' = > \ $ check ,
'strict!' = > \ $ check ,
'ignore=s' = > \ @ ignore ,
'types=s' = > \ @ use ,
'show-types!' = > \ $ show_types ,
'max-line-length=i' = > \ $ max_line_length ,
'root=s' = > \ $ root ,
'summary!' = > \ $ summary ,
'mailback!' = > \ $ mailback ,
'summary-file!' = > \ $ summary_file ,
'fix!' = > \ $ fix ,
'fix-inplace!' = > \ $ fix_inplace ,
'ignore-perl-version!' = > \ $ ignore_perl_version ,
'debug=s' = > \ % debug ,
'test-only=s' = > \ $ tst_only ,
'h|help' = > \ $ help ,
'version' = > \ $ help
) or help ( 1 ) ;
help ( 0 ) if ( $ help ) ;
$ fix = 1 if ( $ fix_inplace ) ;
$ check_orig = $ check ;
my $ exit = 0 ;
if ( $ ^ V && $ ^ V lt $ minimum_perl_version ) {
printf "$P: requires at least perl version %vd\n" , $ minimum_perl_version ;
if ( ! $ ignore_perl_version ) {
exit ( 1 ) ;
}
}
if ( $# ARGV < 0 ) {
print "$P: no input files\n" ;
exit ( 1 ) ;
}
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 ( $ quiet == 0 && keys %$ hashRef ) {
print "NOTE: $prefix message types:" ;
foreach my $ word ( sort keys %$ hashRef ) {
print " $word" ;
}
print "\n\n" ;
}
}
hash_save_array_words ( \ % ignore_type , \ @ ignore ) ;
hash_save_array_words ( \ % use_type , \ @ use ) ;
my $ dbg_values = 0 ;
my $ dbg_possible = 0 ;
my $ dbg_type = 0 ;
my $ dbg_attr = 0 ;
for my $ key ( keys % debug ) {
## 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_glusterfs_tree ( $ root ) ) {
die "$P: $root: --root does not point at a valid tree\n" ;
}
} else {
if ( top_of_glusterfs_tree ( '.' ) ) {
$ root = '.' ;
} elsif ( $ 0 =~ m @(.*)/extras/[^/]*$@ &&
top_of_glusterfs_tree ( $ 1 ) ) {
$ root = $ 1 ;
}
}
if ( ! defined $ root ) {
print "Must be run from the top-level dir. of a GlusterFS tree\n" ;
exit ( 2 ) ;
}
}
my $ emitted_corrupt = 0 ;
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 |
__init_refok |
__kprobes |
__ref |
__rcu
} x ;
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 } ;
# Notes to $Attribute:
# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
our $ Attribute = qr{
const |
__percpu |
__nocast |
__safe |
__bitwise__ |
__packed__ |
__packed2__ |
__naked |
__maybe_unused |
__always_unused |
__noreturn |
__used |
__cold |
__noclone |
__deprecated |
__read_mostly |
__kprobes |
$ InitAttribute |
____cacheline_aligned |
____cacheline_aligned_in_smp |
____cacheline_internodealigned_in_smp |
__weak
} x ;
our $ Modifier ;
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
} x ;
our $ c90_Keywords = qr{ do|for|while|if|else|return|goto|continue|switch|default|case|break } x ;
our $ NonptrType ;
our $ NonptrTypeWithAttr ;
our $ Type ;
our $ Declare ;
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 $ typeTypedefs = qr{ (?x:
( ? : __ ) ? ( ? : u | s | be | le ) ( ? : 8 | 16 | 32 | 64 ) |
atomic_t
) } ;
our $ logFunctions = qr{ (?x:
printk ( ? : _ratelimited | _once | ) |
( ? : [ a - z0 - 9 ] + _ ) { 1 , 2 } ( ? : printk | emerg | alert | crit | err | warning | warn | notice | info | debug | dbg | vdbg | devel | cont | WARN ) ( ? : _ratelimited | _once | ) |
WARN ( ? : _RATELIMIT | _ONCE | ) |
panic |
MODULE_ [ A - Z_ ] + |
seq_vprintf | seq_printf | seq_puts
) } ;
our $ signature_tags = qr{ (?xi:
Signed - off - by: |
Acked - by: |
Tested - by: |
Reviewed - by: |
Reviewed - on: |
Reported - by: |
Original - author: |
Original - Author: |
Original - Authors: |
Suggested - by: |
To: |
Cc:
) } ;
our $ url_tags = qr{ http:|https: } ;
our @ typeList = (
qr{ void } ,
qr{ (?:unsigned \ s+)?char } ,
qr{ (?:unsigned \ s+)?short } ,
qr{ (?:unsigned \ s+)?int } ,
qr{ (?:unsigned \ s+)?long } ,
qr{ (?:unsigned \ s+)?long \ s+int } ,
qr{ (?:unsigned \ s+)?long \ s+long } ,
qr{ (?:unsigned \ s+)?long \ s+long \ s+int } ,
qr{ unsigned } ,
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 } ,
) ;
our @ typeListWithAttr = (
@ typeList ,
qr{ struct \ s+$InitAttribute \ s+$Ident } ,
qr{ union \ s+$InitAttribute \ s+$Ident } ,
) ;
our @ modifierList = (
qr{ fastcall } ,
) ;
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)_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 ] ;
}
our $ declaration_macros = qr{ (?x:
( ? : $ Storage \ s + ) ? ( ? : DECLARE | DEFINE ) _ [ A - Z ] + \ s * \ ( |
( ? : $ Storage \ s + ) ? LIST_HEAD \ s * \ (
) } ;
our $ allowed_asm_includes = qr{ (?x:
irq |
memory
) } ;
# memory.h: ARM has a custom one
sub build_types {
my $ mods = "(?x:\n" . join ( "|\n " , @ modifierList ) . "\n)" ;
my $ all = "(?x:\n" . join ( "|\n " , @ typeList ) . "\n)" ;
my $ allWithAttr = "(?x:\n" . join ( "|\n " , @ typeListWithAttr ) . "\n)" ;
$ Modifier = qr{ (?:$Attribute|$Sparse|$mods) } ;
$ NonptrType = qr{
( ? : $ Modifier \ s + | const \ s + ) *
( ? :
( ? : typeof | __typeof__ ) \ s * \ ( [ ^ \ ) ] * \ ) |
( ? : $ typeTypedefs \ b ) |
( ? : $ { all } \ b )
)
( ? : \ s + $ Modifier | \ s + const ) *
} x ;
$ NonptrTypeWithAttr = qr{
( ? : $ Modifier \ s + | const \ s + ) *
( ? :
( ? : typeof | __typeof__ ) \ s * \ ( [ ^ \ ) ] * \ ) |
( ? : $ typeTypedefs \ b ) |
( ? : $ { allWithAttr } \ b )
)
( ? : \ s + $ Modifier | \ s + const ) *
} x ;
$ Type = qr{
$ NonptrType
( ? : ( ? : \ s | \ * | \ [ \ ] ) + \ s * const | ( ? : \ s | \ * | \ [ \ ] ) + | ( ? : \ s * \ [ \ s * \ ] ) + ) ?
( ? : \ s + $ Inline | \ s + $ Modifier ) *
} x ;
$ Declare = qr{ (?:$Storage \ s+(?:$Inline \ s+)?)?$Type } ;
}
build_types ( ) ;
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) } ;
sub deparenthesize {
my ( $ string ) = @ _ ;
return "" if ( ! defined ( $ string ) ) ;
while ( $ string =~ /^\s*\(.*\)\s*$/ ) {
$ string =~ s@^\s*\(\s*@@ ;
$ string =~ s@\s*\)\s*$@@ ;
}
$ string =~ s@\s+@ @g ;
return $ string ;
}
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 ;
}
}
}
my $ camelcase_seeded = 0 ;
sub seed_camelcase_includes {
return if ( $ camelcase_seeded ) ;
my $ files ;
my $ camelcase_cache = "" ;
my @ include_files = ( ) ;
$ camelcase_seeded = 1 ;
if ( - e ".git" ) {
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" ;
} else {
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 ;
}
if ( - e ".git" ) {
$ 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 ) ;
}
}
$ chk_signoff = 0 if ( $ file ) ;
my @ rawlines = ( ) ;
my @ lines = ( ) ;
my @ fixed = ( ) ;
my $ vname ;
for my $ filename ( @ ARGV ) {
my $ FILE ;
if ( $ file ) {
open ( $ FILE , '-|' , "diff -u /dev/null $filename" ) ||
die "$P: $filename: diff failed - $!\n" ;
} elsif ( $ filename eq '-' ) {
open ( $ FILE , '<&STDIN' ) ;
} else {
open ( $ FILE , '<' , "$filename" ) ||
die "$P: $filename: open failed - $!\n" ;
}
if ( $ filename eq '-' ) {
$ vname = 'Your patch' ;
} else {
$ vname = $ filename ;
}
while ( <$FILE> ) {
chomp ;
push ( @ rawlines , $ _ ) ;
}
close ( $ FILE ) ;
if ( ! process ( $ filename ) ) {
$ exit = 1 ;
}
@ rawlines = ( ) ;
@ lines = ( ) ;
@ fixed = ( ) ;
}
exit ( $ exit ) ;
sub top_of_glusterfs_tree {
my ( $ root ) = @ _ ;
# Add here if the tree changes
my @ tree_check = (
"api" ,
"AUTHORS" ,
"autogen.sh" ,
"build-aux" ,
"ChangeLog" ,
"cli" ,
"configure.ac" ,
"contrib" ,
"CONTRIBUTING" ,
"COPYING-GPLV2" ,
"COPYING-LGPLV3" ,
"doc" ,
"extras" ,
"geo-replication" ,
"glusterfs-api.pc.in" ,
"glusterfsd" ,
"glusterfs.spec.in" ,
2015-03-02 16:24:05 +01:00
"heal" ,
2014-06-25 21:22:49 -07:00
"INSTALL" ,
"libgfchangelog.pc.in" ,
"libglusterfs" ,
"MAINTAINERS" ,
"Makefile.am" ,
"NEWS" ,
2015-03-02 16:24:05 +01:00
"README.md" ,
2014-06-25 21:22:49 -07:00
"rfc.sh" ,
"rpc" ,
"run-tests.sh" ,
"tests" ,
"THANKS" ,
"xlators" ,
) ;
foreach my $ check ( @ tree_check ) {
if ( ! - e $ root . '/' . $ check ) {
return 0 ;
}
}
return 1 ;
}
sub parse_email {
my ( $ formatted_email ) = @ _ ;
my $ name = "" ;
my $ address = "" ;
my $ comment = "" ;
if ( $ formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/ ) {
$ name = $ 1 ;
$ address = $ 2 ;
$ comment = $ 3 if defined $ 3 ;
} elsif ( $ formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/ ) {
$ address = $ 1 ;
$ comment = $ 2 if defined $ 2 ;
} elsif ( $ formatted_email =~ /(\S+\@\S+)(.*)$/ ) {
$ address = $ 1 ;
$ comment = $ 2 if defined $ 2 ;
$ formatted_email =~ s/$address.*$// ;
$ name = $ formatted_email ;
$ name = trim ( $ name ) ;
$ name =~ s/^\"|\"$//g ;
# If there's a name left after stripping spaces and
# leading quotes, and the address doesn't have both
# leading and trailing angle brackets, the address
# is invalid. ie:
# "joe smith joe@smith.com" bad
# "joe smith <joe@smith.com" bad
if ( $ name ne "" && $ address !~ /^<[^>]+>$/ ) {
$ name = "" ;
$ address = "" ;
$ comment = "" ;
}
}
$ name = trim ( $ name ) ;
$ name =~ s/^\"|\"$//g ;
$ address = trim ( $ address ) ;
$ address =~ s/^\<|\>$//g ;
if ( $ name =~ /[^\w \-]/i ) { ##has "must quote" chars
$ name =~ s/(?<!\\)"/\\"/g ; ##escape quotes
$ name = "\"$name\"" ;
}
return ( $ name , $ address , $ comment ) ;
}
sub format_email {
my ( $ name , $ address ) = @ _ ;
my $ formatted_email ;
$ name = trim ( $ name ) ;
$ name =~ s/^\"|\"$//g ;
$ address = trim ( $ address ) ;
if ( $ name =~ /[^\w \-]/i ) { ##has "must quote" chars
$ name =~ s/(?<!\\)"/\\"/g ; ##escape quotes
$ name = "\"$name\"" ;
}
if ( "$name" eq "" ) {
$ formatted_email = "$address" ;
} else {
$ formatted_email = "$name <$address>" ;
}
return $ formatted_email ;
}
sub which_conf {
my ( $ conf ) = @ _ ;
foreach my $ path ( split ( /:/ , ".:$ENV{HOME}:.scripts" ) ) {
if ( - e "$path/$conf" ) {
return "$path/$conf" ;
}
}
return "" ;
}
sub expand_tabs {
my ( $ str ) = @ _ ;
my $ res = '' ;
my $ n = 0 ;
for my $ c ( split ( // , $ str ) ) {
if ( $ c eq "\t" ) {
$ res . = ' ' ;
$ n + + ;
for ( ; ( $ n % 8 ) != 0 ; $ n + + ) {
$ res . = ' ' ;
}
next ;
}
$ res . = $ c ;
$ n + + ;
}
return $ res ;
}
sub copy_spacing {
( my $ res = shift ) =~ tr /\t/ / c ;
return $ res ;
}
sub line_stats {
my ( $ line ) = @ _ ;
# Drop the diff line leader and expand tabs
$ line =~ s/^.// ;
$ line = expand_tabs ( $ line ) ;
# Pick the indent from the front of the line.
my ( $ white ) = ( $ line =~ /^(\s*)/ ) ;
return ( length ( $ line ) , length ( $ white ) ) ;
}
my $ sanitise_quote = '' ;
sub sanitise_line_reset {
my ( $ in_comment ) = @ _ ;
if ( $ in_comment ) {
$ sanitise_quote = '*/' ;
} else {
$ sanitise_quote = '' ;
}
}
sub sanitise_line {
my ( $ line ) = @ _ ;
my $ res = '' ;
my $ l = '' ;
my $ qlen = 0 ;
my $ off = 0 ;
my $ c ;
# Always copy over the diff marker.
$ res = substr ( $ line , 0 , 1 ) ;
for ( $ off = 1 ; $ off < length ( $ line ) ; $ off + + ) {
$ c = substr ( $ line , $ off , 1 ) ;
# Comments we are wacking completly including the begin
# and end, all to $;.
if ( $ sanitise_quote eq '' && substr ( $ line , $ off , 2 ) eq '/*' ) {
$ sanitise_quote = '*/' ;
substr ( $ res , $ off , 2 , "$;$;" ) ;
$ off + + ;
next ;
}
if ( $ sanitise_quote eq '*/' && substr ( $ line , $ off , 2 ) eq '*/' ) {
$ sanitise_quote = '' ;
substr ( $ res , $ off , 2 , "$;$;" ) ;
$ off + + ;
next ;
}
if ( $ sanitise_quote eq '' && substr ( $ line , $ off , 2 ) eq '//' ) {
$ sanitise_quote = '//' ;
substr ( $ res , $ off , 2 , $ sanitise_quote ) ;
$ off + + ;
next ;
}
# A \ in a string means ignore the next character.
if ( ( $ sanitise_quote eq "'" || $ sanitise_quote eq '"' ) &&
$ c eq "\\" ) {
substr ( $ res , $ off , 2 , 'XX' ) ;
$ off + + ;
next ;
}
# Regular quotes.
if ( $ c eq "'" || $ c eq '"' ) {
if ( $ sanitise_quote eq '' ) {
$ sanitise_quote = $ c ;
substr ( $ res , $ off , 1 , $ c ) ;
next ;
} elsif ( $ sanitise_quote eq $ c ) {
$ sanitise_quote = '' ;
}
}
#print "c<$c> SQ<$sanitise_quote>\n";
if ( $ off != 0 && $ sanitise_quote eq '*/' && $ c ne "\t" ) {
substr ( $ res , $ off , 1 , $; ) ;
} elsif ( $ off != 0 && $ sanitise_quote eq '//' && $ c ne "\t" ) {
substr ( $ res , $ off , 1 , $; ) ;
} elsif ( $ off != 0 && $ sanitise_quote && $ c ne "\t" ) {
substr ( $ res , $ off , 1 , 'X' ) ;
} else {
substr ( $ res , $ off , 1 , $ c ) ;
}
}
if ( $ sanitise_quote eq '//' ) {
$ sanitise_quote = '' ;
}
# The pathname on a #include may be surrounded by '<' and '>'.
if ( $ res =~ /^.\s*\#\s*include\s+\<(.*)\>/ ) {
my $ clean = 'X' x length ( $ 1 ) ;
$ res =~ s@\<.*\>@<$clean>@ ;
# The whole of a #error is a string.
} elsif ( $ res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/ ) {
my $ clean = 'X' x length ( $ 1 ) ;
$ res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@ ;
}
return $ res ;
}
sub get_quoted_string {
my ( $ line , $ rawline ) = @ _ ;
return "" if ( $ line !~ m/(\"[X]+\")/g ) ;
return substr ( $ rawline , $- [ 0 ] , $+ [ 0 ] - $- [ 0 ] ) ;
}
sub ctx_statement_block {
my ( $ linenr , $ remain , $ off ) = @ _ ;
my $ line = $ linenr - 1 ;
my $ blk = '' ;
my $ soff = $ off ;
my $ coff = $ off - 1 ;
my $ coff_set = 0 ;
my $ loff = 0 ;
my $ type = '' ;
my $ level = 0 ;
my @ stack = ( ) ;
my $ p ;
my $ c ;
my $ len = 0 ;
my $ remainder ;
while ( 1 ) {
@ stack = ( [ '' , 0 ] ) if ( $# stack == - 1 ) ;
#warn "CSB: blk<$blk> remain<$remain>\n";
# If we are about to drop off the end, pull in more
# context.
if ( $ off >= $ len ) {
for ( ; $ remain > 0 ; $ line + + ) {
last if ( ! defined $ lines [ $ line ] ) ;
next if ( $ lines [ $ line ] =~ /^-/ ) ;
$ remain - - ;
$ loff = $ len ;
$ blk . = $ lines [ $ line ] . "\n" ;
$ len = length ( $ blk ) ;
$ line + + ;
last ;
}
# Bail if there is no further context.
#warn "CSB: blk<$blk> off<$off> len<$len>\n";
if ( $ off >= $ len ) {
last ;
}
if ( $ level == 0 && substr ( $ blk , $ off ) =~ /^.\s*#\s*define/ ) {
$ level + + ;
$ type = '#' ;
}
}
$ p = $ c ;
$ c = substr ( $ blk , $ off , 1 ) ;
$ remainder = substr ( $ blk , $ off ) ;
#warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
# Handle nested #if/#else.
if ( $ remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/ ) {
push ( @ stack , [ $ type , $ level ] ) ;
} elsif ( $ remainder =~ /^#\s*(?:else|elif)\b/ ) {
( $ type , $ level ) = @ { $ stack [ $# stack - 1 ] } ;
} elsif ( $ remainder =~ /^#\s*endif\b/ ) {
( $ type , $ level ) = @ { pop ( @ stack ) } ;
}
# Statement ends at the ';' or a close '}' at the
# outermost level.
if ( $ level == 0 && $ c eq ';' ) {
last ;
}
# An else is really a conditional as long as its not else if
if ( $ level == 0 && $ coff_set == 0 &&
( ! defined ( $ p ) || $ p =~ /(?:\s|\}|\+)/ ) &&
$ remainder =~ /^(else)(?:\s|{)/ &&
$ remainder !~ /^else\s+if\b/ ) {
$ coff = $ off + length ( $ 1 ) - 1 ;
$ coff_set = 1 ;
#warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
#warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
}
if ( ( $ type eq '' || $ type eq '(' ) && $ c eq '(' ) {
$ level + + ;
$ type = '(' ;
}
if ( $ type eq '(' && $ c eq ')' ) {
$ level - - ;
$ type = ( $ level != 0 ) ? '(' : '' ;
if ( $ level == 0 && $ coff < $ soff ) {
$ coff = $ off ;
$ coff_set = 1 ;
#warn "CSB: mark coff<$coff>\n";
}
}
if ( ( $ type eq '' || $ type eq '{' ) && $ c eq '{' ) {
$ level + + ;
$ type = '{' ;
}
if ( $ type eq '{' && $ c eq '}' ) {
$ level - - ;
$ type = ( $ level != 0 ) ? '{' : '' ;
if ( $ level == 0 ) {
if ( substr ( $ blk , $ off + 1 , 1 ) eq ';' ) {
$ off + + ;
}
last ;
}
}
# Preprocessor commands end at the newline unless escaped.
if ( $ type eq '#' && $ c eq "\n" && $ p ne "\\" ) {
$ level - - ;
$ type = '' ;
$ off + + ;
last ;
}
$ off + + ;
}
# We are truly at the end, so shuffle to the next line.
if ( $ off == $ len ) {
$ loff = $ len + 1 ;
$ line + + ;
$ remain - - ;
}
my $ statement = substr ( $ blk , $ soff , $ off - $ soff + 1 ) ;
my $ condition = substr ( $ blk , $ soff , $ coff - $ soff + 1 ) ;
#warn "STATEMENT<$statement>\n";
#warn "CONDITION<$condition>\n";
#print "coff<$coff> soff<$off> loff<$loff>\n";
return ( $ statement , $ condition ,
$ line , $ remain + 1 , $ off - $ loff + 1 , $ level ) ;
}
sub statement_lines {
my ( $ stmt ) = @ _ ;
# Strip the diff line prefixes and rip blank lines at start and end.
$ stmt =~ s/(^|\n)./$1/g ;
$ stmt =~ s/^\s*// ;
$ stmt =~ s/\s*$// ;
my @ stmt_lines = ( $ stmt =~ /\n/g ) ;
return $# stmt_lines + 2 ;
}
sub statement_rawlines {
my ( $ stmt ) = @ _ ;
my @ stmt_lines = ( $ stmt =~ /\n/g ) ;
return $# stmt_lines + 2 ;
}
sub statement_block_size {
my ( $ stmt ) = @ _ ;
$ stmt =~ s/(^|\n)./$1/g ;
$ stmt =~ s/^\s*{// ;
$ stmt =~ s/}\s*$// ;
$ stmt =~ s/^\s*// ;
$ stmt =~ s/\s*$// ;
my @ stmt_lines = ( $ stmt =~ /\n/g ) ;
my @ stmt_statements = ( $ stmt =~ /;/g ) ;
my $ stmt_lines = $# stmt_lines + 2 ;
my $ stmt_statements = $# stmt_statements + 1 ;
if ( $ stmt_lines > $ stmt_statements ) {
return $ stmt_lines ;
} else {
return $ stmt_statements ;
}
}
sub ctx_statement_full {
my ( $ linenr , $ remain , $ off ) = @ _ ;
my ( $ statement , $ condition , $ level ) ;
my ( @ chunks ) ;
# Grab the first conditional/block pair.
( $ statement , $ condition , $ linenr , $ remain , $ off , $ level ) =
ctx_statement_block ( $ linenr , $ remain , $ off ) ;
#print "F: c<$condition> s<$statement> remain<$remain>\n";
push ( @ chunks , [ $ condition , $ statement ] ) ;
if ( ! ( $ remain > 0 && $ condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s ) ) {
return ( $ level , $ linenr , @ chunks ) ;
}
# Pull in the following conditional/block pairs and see if they
# could continue the statement.
for ( ; ; ) {
( $ statement , $ condition , $ linenr , $ remain , $ off , $ level ) =
ctx_statement_block ( $ linenr , $ remain , $ off ) ;
#print "C: c<$condition> s<$statement> remain<$remain>\n";
last if ( ! ( $ remain > 0 && $ condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s ) ) ;
#print "C: push\n";
push ( @ chunks , [ $ condition , $ statement ] ) ;
}
return ( $ level , $ linenr , @ chunks ) ;
}
sub ctx_block_get {
my ( $ linenr , $ remain , $ outer , $ open , $ close , $ off ) = @ _ ;
my $ line ;
my $ start = $ linenr - 1 ;
my $ blk = '' ;
my @ o ;
my @ c ;
my @ res = ( ) ;
my $ level = 0 ;
my @ stack = ( $ level ) ;
for ( $ line = $ start ; $ remain > 0 ; $ line + + ) {
next if ( $ rawlines [ $ line ] =~ /^-/ ) ;
$ remain - - ;
$ blk . = $ rawlines [ $ line ] ;
# Handle nested #if/#else.
if ( $ lines [ $ line ] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/ ) {
push ( @ stack , $ level ) ;
} elsif ( $ lines [ $ line ] =~ /^.\s*#\s*(?:else|elif)\b/ ) {
$ level = $ stack [ $# stack - 1 ] ;
} elsif ( $ lines [ $ line ] =~ /^.\s*#\s*endif\b/ ) {
$ level = pop ( @ stack ) ;
}
foreach my $ c ( split ( // , $ lines [ $ line ] ) ) {
##print "C<$c>L<$level><$open$close>O<$off>\n";
if ( $ off > 0 ) {
$ off - - ;
next ;
}
if ( $ c eq $ close && $ level > 0 ) {
$ level - - ;
last if ( $ level == 0 ) ;
} elsif ( $ c eq $ open ) {
$ level + + ;
}
}
if ( ! $ outer || $ level <= 1 ) {
push ( @ res , $ rawlines [ $ line ] ) ;
}
last if ( $ level == 0 ) ;
}
return ( $ level , @ res ) ;
}
sub ctx_block_outer {
my ( $ linenr , $ remain ) = @ _ ;
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 1 , '{' , '}' , 0 ) ;
return @ r ;
}
sub ctx_block {
my ( $ linenr , $ remain ) = @ _ ;
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 0 , '{' , '}' , 0 ) ;
return @ r ;
}
sub ctx_statement {
my ( $ linenr , $ remain , $ off ) = @ _ ;
my ( $ level , @ r ) = ctx_block_get ( $ linenr , $ remain , 0 , '(' , ')' , $ off ) ;
return @ r ;
}
sub ctx_block_level {
my ( $ linenr , $ remain ) = @ _ ;
return ctx_block_get ( $ linenr , $ remain , 0 , '{' , '}' , 0 ) ;
}
sub ctx_statement_level {
my ( $ linenr , $ remain , $ off ) = @ _ ;
return ctx_block_get ( $ linenr , $ remain , 0 , '(' , ')' , $ off ) ;
}
sub ctx_locate_comment {
my ( $ first_line , $ end_line ) = @ _ ;
# Catch a comment on the end of the line itself.
my ( $ current_comment ) = ( $ rawlines [ $ end_line - 1 ] =~ m @.*(/\*.*\*/)\s*(?:\\\s*)?$@ ) ;
return $ current_comment if ( defined $ current_comment ) ;
# Look through the context and try and figure out if there is a
# comment.
my $ in_comment = 0 ;
$ current_comment = '' ;
for ( my $ linenr = $ first_line ; $ linenr < $ end_line ; $ linenr + + ) {
my $ line = $ rawlines [ $ linenr - 1 ] ;
#warn " $line\n";
if ( $ linenr == $ first_line and $ line =~ m @^.\s*\*@ ) {
$ in_comment = 1 ;
}
if ( $ line =~ m @/\*@ ) {
$ in_comment = 1 ;
}
if ( ! $ in_comment && $ current_comment ne '' ) {
$ current_comment = '' ;
}
$ current_comment . = $ line . "\n" if ( $ in_comment ) ;
if ( $ line =~ m @\*/@ ) {
$ in_comment = 0 ;
}
}
chomp ( $ current_comment ) ;
return ( $ current_comment ) ;
}
sub ctx_has_comment {
my ( $ first_line , $ end_line ) = @ _ ;
my $ cmt = ctx_locate_comment ( $ first_line , $ end_line ) ;
##print "LINE: $rawlines[$end_line - 1 ]\n";
##print "CMMT: $cmt\n";
return ( $ cmt ne '' ) ;
}
sub raw_line {
my ( $ linenr , $ cnt ) = @ _ ;
my $ offset = $ linenr - 1 ;
$ cnt + + ;
my $ line ;
while ( $ cnt ) {
$ line = $ rawlines [ $ offset + + ] ;
next if ( defined ( $ line ) && $ line =~ /^-/ ) ;
$ cnt - - ;
}
return $ line ;
}
sub cat_vet {
my ( $ vet ) = @ _ ;
my ( $ res , $ coded ) ;
$ res = '' ;
while ( $ vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g ) {
$ res . = $ 1 ;
if ( $ 2 ne '' ) {
$ coded = sprintf ( "^%c" , unpack ( 'C' , $ 2 ) + 64 ) ;
$ res . = $ coded ;
}
}
$ res =~ s/$/\$/ ;
return $ res ;
}
my $ av_preprocessor = 0 ;
my $ av_pending ;
my @ av_paren_type ;
my $ av_pend_colon ;
sub annotate_reset {
$ av_preprocessor = 0 ;
$ av_pending = '_' ;
@ av_paren_type = ( 'E' ) ;
$ av_pend_colon = 'O' ;
}
sub annotate_values {
my ( $ stream , $ type ) = @ _ ;
my $ res ;
my $ var = '_' x length ( $ stream ) ;
my $ cur = $ stream ;
print "$stream\n" if ( $ dbg_values > 1 ) ;
while ( length ( $ cur ) ) {
@ av_paren_type = ( 'E' ) if ( $# av_paren_type < 0 ) ;
print " <" . join ( '' , @ av_paren_type ) .
"> <$type> <$av_pending>" if ( $ dbg_values > 1 ) ;
if ( $ cur =~ /^(\s+)/o ) {
print "WS($1)\n" if ( $ dbg_values > 1 ) ;
if ( $ 1 =~ /\n/ && $ av_preprocessor ) {
$ type = pop ( @ av_paren_type ) ;
$ av_preprocessor = 0 ;
}
} elsif ( $ cur =~ /^(\(\s*$Type\s*)\)/ && $ av_pending eq '_' ) {
print "CAST($1)\n" if ( $ dbg_values > 1 ) ;
push ( @ av_paren_type , $ type ) ;
$ type = 'c' ;
} elsif ( $ cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/ ) {
print "DECLARE($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'T' ;
} elsif ( $ cur =~ /^($Modifier)\s*/ ) {
print "MODIFIER($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'T' ;
} elsif ( $ cur =~ /^(\#\s*define\s*$Ident)(\(?)/o ) {
print "DEFINE($1,$2)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ type ) ;
if ( $ 2 ne '' ) {
$ av_pending = 'N' ;
}
$ type = 'E' ;
} elsif ( $ cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o ) {
print "UNDEF($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ type ) ;
} elsif ( $ cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o ) {
print "PRE_START($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ type ) ;
push ( @ av_paren_type , $ type ) ;
$ type = 'E' ;
} elsif ( $ cur =~ /^(\#\s*(?:else|elif))/o ) {
print "PRE_RESTART($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
push ( @ av_paren_type , $ av_paren_type [ $# av_paren_type ] ) ;
$ type = 'E' ;
} elsif ( $ cur =~ /^(\#\s*(?:endif))/o ) {
print "PRE_END($1)\n" if ( $ dbg_values > 1 ) ;
$ av_preprocessor = 1 ;
# Assume all arms of the conditional end as this
# one does, and continue as if the #endif was not here.
pop ( @ av_paren_type ) ;
push ( @ av_paren_type , $ type ) ;
$ type = 'E' ;
} elsif ( $ cur =~ /^(\\\n)/o ) {
print "PRECONT($1)\n" if ( $ dbg_values > 1 ) ;
} elsif ( $ cur =~ /^(__attribute__)\s*\(?/o ) {
print "ATTR($1)\n" if ( $ dbg_values > 1 ) ;
$ av_pending = $ type ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(sizeof)\s*(\()?/o ) {
print "SIZEOF($1)\n" if ( $ dbg_values > 1 ) ;
if ( defined $ 2 ) {
$ av_pending = 'V' ;
}
$ type = 'N' ;
} elsif ( $ cur =~ /^(if|while|for)\b/o ) {
print "COND($1)\n" if ( $ dbg_values > 1 ) ;
$ av_pending = 'E' ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(case)/o ) {
print "CASE($1)\n" if ( $ dbg_values > 1 ) ;
$ av_pend_colon = 'C' ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(return|else|goto|typeof|__typeof__)\b/o ) {
print "KEYWORD($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(\()/o ) {
print "PAREN('$1')\n" if ( $ dbg_values > 1 ) ;
push ( @ av_paren_type , $ av_pending ) ;
$ av_pending = '_' ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(\))/o ) {
my $ new_type = pop ( @ av_paren_type ) ;
if ( $ new_type ne '_' ) {
$ type = $ new_type ;
print "PAREN('$1') -> $type\n"
if ( $ dbg_values > 1 ) ;
} else {
print "PAREN('$1')\n" if ( $ dbg_values > 1 ) ;
}
} elsif ( $ cur =~ /^($Ident)\s*\(/o ) {
print "FUNC($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'V' ;
$ av_pending = 'V' ;
} elsif ( $ cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/ ) {
if ( defined $ 2 && $ type eq 'C' || $ type eq 'T' ) {
$ av_pend_colon = 'B' ;
} elsif ( $ type eq 'E' ) {
$ av_pend_colon = 'L' ;
}
print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ( $ dbg_values > 1 ) ;
$ type = 'V' ;
} elsif ( $ cur =~ /^($Ident|$Constant)/o ) {
print "IDENT($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'V' ;
} elsif ( $ cur =~ /^($Assignment)/o ) {
print "ASSIGN($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(;|{|})/ ) {
print "END($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'E' ;
$ av_pend_colon = 'O' ;
} elsif ( $ cur =~ /^(,)/ ) {
print "COMMA($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'C' ;
} elsif ( $ cur =~ /^(\?)/o ) {
print "QUESTION($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(:)/o ) {
print "COLON($1,$av_pend_colon)\n" if ( $ dbg_values > 1 ) ;
substr ( $ var , length ( $ res ) , 1 , $ av_pend_colon ) ;
if ( $ av_pend_colon eq 'C' || $ av_pend_colon eq 'L' ) {
$ type = 'E' ;
} else {
$ type = 'N' ;
}
$ av_pend_colon = 'O' ;
} elsif ( $ cur =~ /^(\[)/o ) {
print "CLOSE($1)\n" if ( $ dbg_values > 1 ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o ) {
my $ variant ;
print "OPV($1)\n" if ( $ dbg_values > 1 ) ;
if ( $ type eq 'V' ) {
$ variant = 'B' ;
} else {
$ variant = 'U' ;
}
substr ( $ var , length ( $ res ) , 1 , $ variant ) ;
$ type = 'N' ;
} elsif ( $ cur =~ /^($Operators)/o ) {
print "OP($1)\n" if ( $ dbg_values > 1 ) ;
if ( $ 1 ne '++' && $ 1 ne '--' ) {
$ type = 'N' ;
}
} elsif ( $ cur =~ /(^.)/o ) {
print "C($1)\n" if ( $ dbg_values > 1 ) ;
}
if ( defined $ 1 ) {
$ cur = substr ( $ cur , length ( $ 1 ) ) ;
$ res . = $ type x length ( $ 1 ) ;
}
}
return ( $ res , $ var ) ;
}
sub possible {
my ( $ possible , $ line ) = @ _ ;
my $ notPermitted = qr{ (?:
^ ( ? :
$ Modifier |
$ Storage |
$ Type |
DEFINE_ \ S +
) $|
^ ( ? :
goto |
return |
case |
else |
asm | __asm__ |
do |
\ #|
\ #\#|
) ( ? : \ s | $ ) |
^ ( ? : typedef | struct | enum ) \ b
) } x ;
warn "CHECK<$possible> ($line)\n" if ( $ dbg_possible > 2 ) ;
if ( $ possible !~ $ notPermitted ) {
# Check for modifiers.
$ possible =~ s/\s*$Storage\s*//g ;
$ possible =~ s/\s*$Sparse\s*//g ;
if ( $ possible =~ /^\s*$/ ) {
} elsif ( $ possible =~ /\s/ ) {
$ possible =~ s/\s*$Type\s*//g ;
for my $ modifier ( split ( ' ' , $ possible ) ) {
if ( $ modifier !~ $ notPermitted ) {
warn "MODIFIER: $modifier ($possible) ($line)\n" if ( $ dbg_possible ) ;
push ( @ modifierList , $ modifier ) ;
}
}
} else {
warn "POSSIBLE: $possible ($line)\n" if ( $ dbg_possible ) ;
push ( @ typeList , $ possible ) ;
}
build_types ( ) ;
} else {
warn "NOTPOSS: $possible ($line)\n" if ( $ dbg_possible > 1 ) ;
}
}
my $ prefix = '' ;
sub show_type {
my ( $ type ) = @ _ ;
return defined $ use_type { $ type } if ( scalar keys % use_type > 0 ) ;
return ! defined $ ignore_type { $ type } ;
}
sub report {
my ( $ level , $ type , $ msg ) = @ _ ;
if ( ! show_type ( $ type ) ||
( defined $ tst_only && $ msg !~ /\Q$tst_only\E/ ) ) {
return 0 ;
}
my $ line ;
if ( $ show_types ) {
$ line = "$prefix$level:$type: $msg\n" ;
} else {
$ line = "$prefix$level: $msg\n" ;
}
$ line = ( split ( '\n' , $ line ) ) [ 0 ] . "\n" if ( $ terse ) ;
if ( $ quiet == 0 ) {
push ( our @ report , $ line ) ;
}
return 1 ;
}
sub report_dump {
our @ report ;
}
sub ERROR {
my ( $ type , $ msg ) = @ _ ;
if ( report ( "ERROR" , $ type , $ msg ) ) {
our $ clean = 0 ;
our $ cnt_error + + ;
return 1 ;
}
return 0 ;
}
sub WARN {
my ( $ type , $ msg ) = @ _ ;
if ( report ( "WARNING" , $ type , $ msg ) ) {
## Warning is okay to submit
our $ clean = 0 ;
our $ cnt_warn + + ;
return 1 ;
}
return 0 ;
}
sub CHK {
my ( $ type , $ msg ) = @ _ ;
if ( $ check && report ( "CHECK" , $ type , $ msg ) ) {
our $ clean = 0 ;
our $ cnt_chk + + ;
return 1 ;
}
return 0 ;
}
sub check_absolute_file {
my ( $ absolute , $ herecurr ) = @ _ ;
my $ file = $ absolute ;
##print "absolute<$absolute>\n";
# See if any suffix of this path is a path within the tree.
while ( $ file =~ s@^[^/]*/@@ ) {
if ( - f "$root/$file" ) {
##print "file<$file>\n";
last ;
}
}
if ( ! - f _ ) {
return 0 ;
}
# It is, so see if the prefix is acceptable.
my $ prefix = $ absolute ;
substr ( $ prefix , - length ( $ file ) ) = '' ;
##print "prefix<$prefix>\n";
if ( $ prefix ne ".../" ) {
WARN ( "USE_RELATIVE_PATH" ,
"use relative pathname instead of absolute in changelog text\n" . $ herecurr ) ;
}
}
sub trim {
my ( $ string ) = @ _ ;
$ string =~ s/^\s+|\s+$//g ;
return $ string ;
}
sub ltrim {
my ( $ string ) = @ _ ;
$ string =~ s/^\s+// ;
return $ string ;
}
sub rtrim {
my ( $ string ) = @ _ ;
$ string =~ s/\s+$// ;
return $ string ;
}
sub string_find_replace {
my ( $ string , $ find , $ replace ) = @ _ ;
$ string =~ s/$find/$replace/g ;
return $ string ;
}
sub tabify {
my ( $ leading ) = @ _ ;
my $ source_indent = 8 ;
my $ max_spaces_before_tab = $ source_indent - 1 ;
my $ spaces_to_tab = " " x $ source_indent ;
#convert leading spaces to tabs
1 while $ leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g ;
#Remove spaces before a tab
1 while $ leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g ;
return "$leading" ;
}
sub pos_last_openparen {
my ( $ line ) = @ _ ;
my $ pos = 0 ;
my $ opens = $ line =~ tr /\(/ \ ( / ;
my $ closes = $ line =~ tr /\)/ \ ) / ;
my $ last_openparen = 0 ;
if ( ( $ opens == 0 ) || ( $ closes >= $ opens ) ) {
return - 1 ;
}
my $ len = length ( $ line ) ;
for ( $ pos = 0 ; $ pos < $ len ; $ pos + + ) {
my $ string = substr ( $ line , $ pos ) ;
if ( $ string =~ /^($FuncArg|$balanced_parens)/ ) {
$ pos += length ( $ 1 ) - 1 ;
} elsif ( substr ( $ line , $ pos , 1 ) eq '(' ) {
$ last_openparen = $ pos ;
} elsif ( index ( $ string , '(' ) == - 1 ) {
last ;
}
}
return length ( expand_tabs ( substr ( $ line , 0 , $ last_openparen ) ) ) + 1 ;
}
sub process {
my $ filename = shift ;
my $ linenr = 0 ;
my $ prevline = "" ;
my $ prevrawline = "" ;
my $ stashline = "" ;
my $ stashrawline = "" ;
my $ length ;
my $ indent ;
my $ previndent = 0 ;
my $ stashindent = 0 ;
our $ clean = 1 ;
my $ signoff = 0 ;
2015-03-19 10:38:23 +01:00
my $ subject_trailing_dot = 0 ;
2014-06-25 21:22:49 -07:00
my $ is_patch = 0 ;
my $ in_header_lines = 1 ;
my $ in_commit_log = 0 ; #Scanning lines before patch
my $ non_utf8_charset = 0 ;
our @ report = ( ) ;
our $ cnt_lines = 0 ;
our $ cnt_error = 0 ;
our $ cnt_warn = 0 ;
our $ cnt_chk = 0 ;
# Trace the real file/line as we go.
my $ realfile = '' ;
my $ realline = 0 ;
my $ realcnt = 0 ;
my $ here = '' ;
my $ in_comment = 0 ;
my $ comment_edge = 0 ;
my $ first_line = 0 ;
my $ p1_prefix = '' ;
my $ prev_values = 'E' ;
# suppression flags
my % suppress_ifbraces ;
my % suppress_whiletrailers ;
my % suppress_export ;
my $ suppress_statement = 0 ;
my % signatures = ( ) ;
# Pre-scan the patch sanitizing the lines.
# Pre-scan the patch looking for any __setup documentation.
#
my @ setup_docs = ( ) ;
my $ setup_docs = 0 ;
my $ camelcase_file_seeded = 0 ;
sanitise_line_reset ( ) ;
my $ line ;
foreach my $ rawline ( @ rawlines ) {
$ linenr + + ;
$ line = $ rawline ;
push ( @ fixed , $ rawline ) if ( $ fix ) ;
if ( $ rawline =~ /^\+\+\+\s+(\S+)/ ) {
$ setup_docs = 0 ;
if ( $ 1 =~ m @Documentation/kernel-parameters.txt$@ ) {
$ setup_docs = 1 ;
}
#next;
}
if ( $ rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/ ) {
$ realline = $ 1 - 1 ;
if ( defined $ 2 ) {
$ realcnt = $ 3 + 1 ;
} else {
$ realcnt = 1 + 1 ;
}
$ in_comment = 0 ;
# Guestimate if this is a continuing comment. Run
# the context looking for a comment "edge". If this
# edge is a close comment then we must be in a comment
# at context start.
my $ edge ;
my $ cnt = $ realcnt ;
for ( my $ ln = $ linenr + 1 ; $ cnt > 0 ; $ ln + + ) {
next if ( defined $ rawlines [ $ ln - 1 ] &&
$ rawlines [ $ ln - 1 ] =~ /^-/ ) ;
$ cnt - - ;
#print "RAW<$rawlines[$ln - 1]>\n";
last if ( ! defined $ rawlines [ $ ln - 1 ] ) ;
if ( $ rawlines [ $ ln - 1 ] =~ m @(/\*|\*/)@ &&
$ rawlines [ $ ln - 1 ] !~ m @"[^"]*(?:/\*|\*/)[^"]*"@ ) {
( $ edge ) = $ 1 ;
last ;
}
}
if ( defined $ edge && $ edge eq '*/' ) {
$ in_comment = 1 ;
}
# Guestimate if this is a continuing comment. If this
# is the start of a diff block and this line starts
# ' *' then it is very likely a comment.
if ( ! defined $ edge &&
$ rawlines [ $ linenr ] =~ m @^.\s*(?:\*\*+| \*)(?:\s|$)@ )
{
$ in_comment = 1 ;
}
##print "COMMENT:$in_comment edge<$edge> $rawline\n";
sanitise_line_reset ( $ in_comment ) ;
} elsif ( $ realcnt && $ rawline =~ /^(?:\+| |$)/ ) {
# Standardise the strings and chars within the input to
# simplify matching -- only bother with positive lines.
$ line = sanitise_line ( $ rawline ) ;
}
push ( @ lines , $ line ) ;
if ( $ realcnt > 1 ) {
$ realcnt - - if ( $ line =~ /^(?:\+| |$)/ ) ;
} else {
$ realcnt = 0 ;
}
#print "==>$rawline\n";
#print "-->$line\n";
if ( $ setup_docs && $ line =~ /^\+/ ) {
push ( @ setup_docs , $ line ) ;
}
}
$ prefix = '' ;
$ realcnt = 0 ;
$ linenr = 0 ;
foreach my $ line ( @ lines ) {
$ linenr + + ;
my $ sline = $ line ; #copy of $line
$ sline =~ s/$;/ /g ; #with comments as spaces
my $ rawline = $ rawlines [ $ linenr - 1 ] ;
#extract the line range in the file after the patch is applied
if ( $ line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/ ) {
$ is_patch = 1 ;
$ first_line = $ linenr + 1 ;
$ realline = $ 1 - 1 ;
if ( defined $ 2 ) {
$ realcnt = $ 3 + 1 ;
} else {
$ realcnt = 1 + 1 ;
}
annotate_reset ( ) ;
$ prev_values = 'E' ;
% suppress_ifbraces = ( ) ;
% suppress_whiletrailers = ( ) ;
% suppress_export = ( ) ;
$ suppress_statement = 0 ;
next ;
# track the line number as we move through the hunk, note that
# new versions of GNU diff omit the leading space on completely
# blank context lines so we need to count that too.
} elsif ( $ line =~ /^( |\+|$)/ ) {
$ realline + + ;
$ realcnt - - if ( $ realcnt != 0 ) ;
# Measure the line length and indent.
( $ length , $ indent ) = line_stats ( $ rawline ) ;
# Track the previous line.
( $ prevline , $ stashline ) = ( $ stashline , $ line ) ;
( $ previndent , $ stashindent ) = ( $ stashindent , $ indent ) ;
( $ prevrawline , $ stashrawline ) = ( $ stashrawline , $ rawline ) ;
#warn "line<$line>\n";
} elsif ( $ realcnt == 1 ) {
$ realcnt - - ;
}
my $ hunk_line = ( $ realcnt != 0 ) ;
#make up the handle for any error we report on this line
$ prefix = "$filename:$realline: " if ( $ emacs && $ file ) ;
$ prefix = "$filename:$linenr: " if ( $ emacs && ! $ file ) ;
$ here = "#$linenr: " if ( ! $ file ) ;
$ here = "#$realline: " if ( $ file ) ;
my $ found_file = 0 ;
# extract the filename as it passes
if ( $ line =~ /^diff --git.*?(\S+)$/ ) {
$ realfile = $ 1 ;
$ realfile =~ s@^([^/]*)/@@ if ( ! $ file ) ;
$ in_commit_log = 0 ;
$ found_file = 1 ;
} elsif ( $ line =~ /^\+\+\+\s+(\S+)/ ) {
$ realfile = $ 1 ;
$ realfile =~ s@^([^/]*)/@@ if ( ! $ file ) ;
$ in_commit_log = 0 ;
$ p1_prefix = $ 1 ;
if ( ! $ file && $ tree && $ p1_prefix ne '' &&
- e "$root/$p1_prefix" ) {
WARN ( "PATCH_PREFIX" ,
"patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n" ) ;
}
$ found_file = 1 ;
}
if ( $ found_file ) {
if ( $ realfile =~ m @^(drivers/net/|net/)@ ) {
$ check = 1 ;
} else {
$ check = $ check_orig ;
}
next ;
}
$ here . = "FILE: $realfile:$realline:" if ( $ realcnt != 0 ) ;
my $ hereline = "$here\n$rawline\n" ;
my $ herecurr = "$here\n$rawline\n" ;
my $ hereprev = "$here\n$prevrawline\n$rawline\n" ;
$ cnt_lines + + if ( $ realcnt != 0 ) ;
# Check for incorrect file permissions
if ( $ line =~ /^new (file )?mode.*[7531]\d{0,2}$/ ) {
my $ permhere = $ here . "FILE: $realfile\n" ;
if ( $ realfile !~ m @scripts/@ &&
$ realfile !~ /\.(py|pl|awk|sh|t)$/ ) {
ERROR ( "EXECUTE_PERMISSIONS" ,
"do not set execute permissions for source files\n" . $ permhere ) ;
}
}
next if ( $ realfile =~ /(checkpatch.pl)/ ) ;
next if ( $ realfile =~ /\.(md|txt|doc|8|pdf|tex)$/ ) ;
2015-03-19 10:38:23 +01:00
# Check that the subject does not have a trailing dot
if ( $ in_header_lines &&
$ line =~ /^Subject: \[PATCH\] (.+)\.(\s*)$/ ) {
$ subject_trailing_dot + + ;
}
2014-06-25 21:22:49 -07:00
# Check the patch for a signoff:
if ( $ line =~ /^\s*signed-off-by:/i ) {
$ signoff + + ;
$ in_commit_log = 0 ;
}
# Check signature styles
if ( ! $ in_header_lines &&
$ line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i ) {
my $ space_before = $ 1 ;
my $ sign_off = $ 2 ;
my $ space_after = $ 3 ;
my $ email = $ 4 ;
my $ ucfirst_sign_off = ucfirst ( lc ( $ sign_off ) ) ;
if ( $ sign_off !~ /$signature_tags/ ) {
WARN ( "BAD_SIGN_OFF" ,
"Non-standard signature: $sign_off\n" . $ herecurr ) ;
}
if ( defined $ space_before && $ space_before ne "" ) {
if ( WARN ( "BAD_SIGN_OFF" ,
"Do not use whitespace before $ucfirst_sign_off\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =
"$ucfirst_sign_off $email" ;
}
}
if ( $ sign_off =~ /-by:$/i && $ sign_off ne $ ucfirst_sign_off ) {
if ( WARN ( "BAD_SIGN_OFF" ,
"'$ucfirst_sign_off' is the preferred signature form\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =
"$ucfirst_sign_off $email" ;
}
}
if ( ! defined $ space_after || $ space_after ne " " ) {
if ( WARN ( "BAD_SIGN_OFF" ,
"Use a single space after $ucfirst_sign_off\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =
"$ucfirst_sign_off $email" ;
}
}
2015-04-12 16:23:55 +01:00
# Check if email is really Gerrit URL
2014-06-25 21:22:49 -07:00
if ( $ email =~ /^($url_tags)(.*)/ ) {
my $ uri = $ 1 ;
my $ url = $ 2 ;
2015-04-12 16:23:55 +01:00
if ( $ uri && $ url !~ /$gerrit_url/ ) {
2014-06-25 21:22:49 -07:00
ERROR ( "BAD_URL" ,
"Unrecognized url address: '$email'\n" . $ herecurr ) ;
}
} else {
my ( $ email_name , $ email_address , $ comment ) = parse_email ( $ email ) ;
my $ suggested_email = format_email ( ( $ email_name , $ email_address ) ) ;
if ( $ suggested_email eq "" ) {
ERROR ( "BAD_SIGN_OFF" ,
"Unrecognized email address: '$email'\n" . $ herecurr ) ;
} else {
my $ dequoted = $ suggested_email ;
$ dequoted =~ s/^"// ;
$ dequoted =~ s/" </ </ ;
# Don't force email to have quotes
# Allow just an angle bracketed address
if ( "$dequoted$comment" ne $ email &&
"<$email_address>$comment" ne $ email &&
"$suggested_email$comment" ne $ email ) {
WARN ( "BAD_SIGN_OFF" ,
"email address '$email' might be better as '$suggested_email$comment'\n" . $ herecurr ) ;
}
}
}
# Check for duplicate signatures
my $ sig_nospace = $ line ;
$ sig_nospace =~ s/\s//g ;
$ sig_nospace = lc ( $ sig_nospace ) ;
if ( defined $ signatures { $ sig_nospace } ) {
WARN ( "BAD_SIGN_OFF" ,
"Duplicate signature\n" . $ herecurr ) ;
} else {
$ signatures { $ sig_nospace } = 1 ;
}
}
# Check for wrappage within a valid hunk of the file
if ( $ realcnt != 0 && $ line !~ m {^(?:\+|-| |\\ No newline|$)} ) {
ERROR ( "CORRUPTED_PATCH" ,
"patch seems to be corrupt (line wrapped?)\n" .
$ herecurr ) if ( ! $ emitted_corrupt + + ) ;
}
# Check for absolute kernel paths.
if ( $ tree ) {
while ( $ line =~ m {(?:^|\s)(/\S*)}g ) {
my $ file = $ 1 ;
if ( $ file =~ m {^(.*?)(?::\d+)+:?$} &&
check_absolute_file ( $ 1 , $ herecurr ) ) {
#
} else {
check_absolute_file ( $ file , $ herecurr ) ;
}
}
}
# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
if ( ( $ realfile =~ /^$/ || $ line =~ /^\+/ ) &&
$ rawline !~ m/^$UTF8*$/ ) {
my ( $ utf8_prefix ) = ( $ rawline =~ /^($UTF8*)/ ) ;
my $ blank = copy_spacing ( $ rawline ) ;
my $ ptr = substr ( $ blank , 0 , length ( $ utf8_prefix ) ) . "^" ;
my $ hereptr = "$hereline$ptr\n" ;
CHK ( "INVALID_UTF8" ,
"Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $ hereptr ) ;
}
# Check if it's the start of a commit log
# (not a header line and we haven't seen the patch filename)
if ( $ in_header_lines && $ realfile =~ /^$/ &&
$ rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i ) {
$ in_header_lines = 0 ;
$ in_commit_log = 1 ;
}
# Check if there is UTF-8 in a commit log when a mail header has explicitly
# declined it, i.e defined some charset where it is missing.
if ( $ in_header_lines &&
$ rawline =~ /^Content-Type:.+charset="(.+)".*$/ &&
$ 1 !~ /utf-8/i ) {
$ non_utf8_charset = 1 ;
}
if ( $ in_commit_log && $ non_utf8_charset && $ realfile =~ /^$/ &&
$ rawline =~ /$NON_ASCII_UTF8/ ) {
WARN ( "UTF8_BEFORE_PATCH" ,
"8-bit UTF-8 used in possible commit log\n" . $ herecurr ) ;
}
# ignore non-hunk lines and lines being removed
next if ( ! $ hunk_line || $ line =~ /^-/ ) ;
#trailing whitespace
if ( $ line =~ /^\+.*\015/ ) {
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
if ( ERROR ( "DOS_LINE_ENDINGS" ,
"DOS line endings\n" . $ herevet ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/[\s\015]+$// ;
}
} elsif ( $ rawline =~ /^\+.*\S\s+$/ || $ rawline =~ /^\+\s+$/ ) {
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
if ( ERROR ( "TRAILING_WHITESPACE" ,
"trailing whitespace\n" . $ herevet ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\s+$// ;
}
$ rpt_cleaners = 1 ;
}
if ( ( $ realfile =~ /Makefile.*/ ) &&
( $ line =~ /\+(EXTRA_[A-Z]+FLAGS).*/ ) ) {
my $ flag = $ 1 ;
my $ replacement = {
'EXTRA_AFLAGS' = > 'asflags-y' ,
'EXTRA_CFLAGS' = > 'ccflags-y' ,
'EXTRA_CPPFLAGS' = > 'cppflags-y' ,
'EXTRA_LDFLAGS' = > 'ldflags-y' ,
} ;
WARN ( "DEPRECATED_VARIABLE" ,
"Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $ herecurr ) if ( $ replacement - > { $ flag } ) ;
}
2016-04-12 11:35:38 -04:00
# check we are in .spec file, then ignore this hunk
next if ( $ realfile eq "glusterfs.spec.in" ) ;
2014-06-25 21:22:49 -07:00
# check we are in a valid source file if not then ignore this hunk
next if ( $ realfile !~ /\.(h|c|pl|py|l|y|sh|in)$/ ) ;
#line length limit
if ( $ line =~ /^\+/ && $ prevrawline !~ /\/\*\*/ &&
$ rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
! ( $ line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ ||
$ line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/ ) &&
$ length > $ max_line_length )
{
WARN ( "LONG_LINE" ,
"line over $max_line_length characters\n" . $ herecurr ) ;
}
# check for spaces before a quoted newline
if ( $ rawline =~ /^.*\".*\s\\n/ ) {
if ( WARN ( "QUOTED_WHITESPACE_BEFORE_NEWLINE" ,
"unnecessary whitespace before a quoted newline\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/^(\+.*\".*)\s+\\n/$1\\n/ ;
}
}
# check for adding lines without a newline.
if ( $ line =~ /^\+/ && defined $ lines [ $ linenr ] && $ lines [ $ linenr ] =~ /^\\ No newline at end of file/ ) {
WARN ( "MISSING_EOF_NEWLINE" ,
"adding a line without newline at end of file\n" . $ herecurr ) ;
}
# check we are in a valid source file C or perl if not then ignore this hunk
next if ( $ realfile !~ /\.(h|c|pl)$/ ) ;
# check for space before tabs.
if ( $ rawline =~ /^\+/ && $ rawline =~ / \t/ ) {
my $ herevet = "$here\n" . cat_vet ( $ rawline ) . "\n" ;
if ( WARN ( "SPACE_BEFORE_TAB" ,
"please, no space before tabs\n" . $ herevet ) &&
$ fix ) {
while ( $ fixed [ $ linenr - 1 ] =~
2014-09-22 10:59:37 -07:00
s/(^\+.*) {8,8}\t/$1\t\t/ ) { }
2014-06-25 21:22:49 -07:00
while ( $ fixed [ $ linenr - 1 ] =~
s/(^\+.*) +\t/$1\t/ ) { }
}
}
# check for && or || at the start of a line
if ( $ rawline =~ /^\+\s*(&&|\|\|)/ ) {
CHK ( "LOGICAL_CONTINUATIONS" ,
"Logical continuations should be on the previous line\n" . $ hereprev ) ;
}
# check multi-line statement indentation matches previous line
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/ ) {
$ prevline =~ /^\+(\t*)(.*)$/ ;
my $ oldindent = $ 1 ;
my $ rest = $ 2 ;
my $ pos = pos_last_openparen ( $ rest ) ;
if ( $ pos >= 0 ) {
$ line =~ /^(\+| )([ \t]*)/ ;
my $ newindent = $ 2 ;
my $ goodtabindent = $ oldindent .
"\t" x ( $ pos / 8 ) .
" " x ( $ pos % 8 ) ;
my $ goodspaceindent = $ oldindent . " " x $ pos ;
if ( $ newindent ne $ goodtabindent &&
$ newindent ne $ goodspaceindent ) {
if ( CHK ( "PARENTHESIS_ALIGNMENT" ,
"Alignment should match open parenthesis\n" . $ hereprev ) &&
$ fix && $ line =~ /^\+/ ) {
$ fixed [ $ linenr - 1 ] =~
s/^\+[ \t]*/\+$goodtabindent/ ;
}
}
}
}
if ( $ line =~ /^\+.*\*[ \t]*\)[ \t]+(?!$Assignment|$Arithmetic)/ ) {
if ( CHK ( "SPACING" ,
"No space is necessary after a cast\n" . $ hereprev ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(\+.*\*[ \t]*\))[ \t]+/$1/ ;
}
}
# check for missing blank lines after declarations
if ( $ sline =~ /^\+\s+\S/ && #Not at char 1
# actual declarations
( $ prevline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ ||
# foo bar; where foo is some local typedef or #define
$ prevline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ ||
# known declaration macros
$ prevline =~ /^\+\s+$declaration_macros/ ) &&
# for "else if" which can look like "$Ident $Ident"
! ( $ prevline =~ /^\+\s+$c90_Keywords\b/ ||
# other possible extensions of declaration lines
$ prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ ||
# not starting a section or a macro "\" extended line
$ prevline =~ /(?:\{\s*|\\)$/ ) &&
# looks like a declaration
! ( $ sline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ ||
# foo bar; where foo is some local typedef or #define
$ sline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ ||
# known declaration macros
$ sline =~ /^\+\s+$declaration_macros/ ||
# start of struct or union or enum
$ sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ ||
# start or end of block or continuation of declaration
$ sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ ||
# bitfield continuation
$ sline =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ ||
# other possible extensions of declaration lines
$ sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/ ) &&
# indentation of previous and current line are the same
( ( $ prevline =~ /\+(\s+)\S/ ) && $ sline =~ /^\+$1\S/ ) ) {
WARN ( "SPACING" ,
"Missing a blank line after declarations\n" . $ hereprev ) ;
}
# check we are in a valid C source file if not then ignore this hunk
next if ( $ realfile !~ /\.(h|c)$/ ) ;
# check for RCS/CVS revision markers
if ( $ rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/ ) {
WARN ( "CVS_KEYWORD" ,
"CVS style keyword markers, these will _not_ be updated\n" . $ herecurr ) ;
}
# Check for potential 'bare' types
my ( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ,
$ realline_next ) ;
#print "LINE<$line>\n";
if ( $ linenr >= $ suppress_statement &&
$ realcnt && $ sline =~ /.\s*\S/ ) {
( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 ) ;
$ stat =~ s/\n./\n /g ;
$ cond =~ s/\n./\n /g ;
#print "linenr<$linenr> <$stat>\n";
# If this statement has no statement boundaries within
# it there is no point in retrying a statement scan
# until we hit end of it.
my $ frag = $ stat ; $ frag =~ s/;+\s*$// ;
if ( $ frag !~ /(?:{|;)/ ) {
#print "skip<$line_nr_next>\n";
$ suppress_statement = $ line_nr_next ;
}
# Find the real next line.
$ realline_next = $ line_nr_next ;
if ( defined $ realline_next &&
( ! defined $ lines [ $ realline_next - 1 ] ||
substr ( $ lines [ $ realline_next - 1 ] , $ off_next ) =~ /^\s*$/ ) ) {
$ realline_next + + ;
}
my $ s = $ stat ;
$ s =~ s/{.*$//s ;
# Ignore goto labels.
if ( $ s =~ /$Ident:\*$/s ) {
# Ignore functions being called
} elsif ( $ s =~ /^.\s*$Ident\s*\(/s ) {
} elsif ( $ s =~ /^.\s*else\b/s ) {
# declarations always start with types
} elsif ( $ prev_values eq 'E' && $ s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s ) {
my $ type = $ 1 ;
$ type =~ s/\s+/ /g ;
possible ( $ type , "A:" . $ s ) ;
# definitions in global scope can only start with types
} elsif ( $ s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s ) {
possible ( $ 1 , "B:" . $ s ) ;
}
# any (foo ... *) is a pointer cast, and foo is a type
while ( $ s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg ) {
possible ( $ 1 , "C:" . $ s ) ;
}
# Check for any sort of function declaration.
# int foo(something bar, other baz);
# void (*store_gdt)(x86_descr_ptr *);
if ( $ prev_values eq 'E' && $ s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s ) {
my ( $ name_len ) = length ( $ 1 ) ;
my $ ctx = $ s ;
substr ( $ ctx , 0 , $ name_len + 1 , '' ) ;
$ ctx =~ s/\)[^\)]*$// ;
for my $ arg ( split ( /\s*,\s*/ , $ ctx ) ) {
if ( $ arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $ arg =~ /^($Ident)$/s ) {
possible ( $ 1 , "D:" . $ s ) ;
}
}
}
}
#
# Checks which may be anchored in the context.
#
# Check for switch () and associated case and default
# statements should be at the same indent.
if ( $ line =~ /\bswitch\s*\(.*\)/ ) {
my $ err = '' ;
my $ sep = '' ;
my @ ctx = ctx_block_outer ( $ linenr , $ realcnt ) ;
shift ( @ ctx ) ;
for my $ ctx ( @ ctx ) {
my ( $ clen , $ cindent ) = line_stats ( $ ctx ) ;
if ( $ ctx =~ /^\+\s*(case\s+|default:)/ &&
$ indent != $ cindent ) {
$ err . = "$sep$ctx\n" ;
$ sep = '' ;
} else {
$ sep = "[...]\n" ;
}
}
if ( $ err ne '' ) {
ERROR ( "SWITCH_CASE_INDENT_LEVEL" ,
"switch and case should be at the same indent\n$hereline$err" ) ;
}
}
# if/while/etc brace do not go on next line, unless defining a do while loop,
# or if that brace on the next line is for something else
if ( $ line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $ line !~ /^.\s*\#/ ) {
my $ pre_ctx = "$1$2" ;
my ( $ level , @ ctx ) = ctx_statement_level ( $ linenr , $ realcnt , 0 ) ;
if ( $ line =~ /^\+\t{6,}/ ) {
WARN ( "DEEP_INDENTATION" ,
"Too many leading tabs - consider code refactoring\n" . $ herecurr ) ;
}
my $ ctx_cnt = $ realcnt - $# ctx - 1 ;
my $ ctx = join ( "\n" , @ ctx ) ;
my $ ctx_ln = $ linenr ;
my $ ctx_skip = $ realcnt ;
while ( $ ctx_skip > $ ctx_cnt || ( $ ctx_skip == $ ctx_cnt &&
defined $ lines [ $ ctx_ln - 1 ] &&
$ lines [ $ ctx_ln - 1 ] =~ /^-/ ) ) {
##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
$ ctx_skip - - if ( ! defined $ lines [ $ ctx_ln - 1 ] || $ lines [ $ ctx_ln - 1 ] !~ /^-/ ) ;
$ ctx_ln + + ;
}
#print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
#print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
if ( $ ctx !~ /{\s*/ && defined ( $ lines [ $ ctx_ln - 1 ] ) && $ lines [ $ ctx_ln - 1 ] =~ /^\+\s*{/ ) {
ERROR ( "OPEN_BRACE" ,
"that open brace { should be on the previous line\n" .
"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n" ) ;
}
if ( $ level == 0 && $ pre_ctx !~ /}\s*while\s*\($/ &&
$ ctx =~ /\)\s*\;\s*$/ &&
defined $ lines [ $ ctx_ln - 1 ] )
{
my ( $ nlength , $ nindent ) = line_stats ( $ lines [ $ ctx_ln - 1 ] ) ;
if ( $ nindent > $ indent ) {
WARN ( "TRAILING_SEMICOLON" ,
"trailing semicolon indicates no statements, indent implies otherwise\n" .
"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n" ) ;
}
}
}
# Check relative indent for conditionals and blocks.
if ( $ line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $ line !~ /^.\s*#/ && $ line !~ /\}\s*while\s*/ ) {
( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 )
if ( ! defined $ stat ) ;
my ( $ s , $ c ) = ( $ stat , $ cond ) ;
substr ( $ s , 0 , length ( $ c ) , '' ) ;
# Make sure we remove the line prefixes as we have
# none on the first line, and are going to readd them
# where necessary.
$ s =~ s/\n./\n/gs ;
# Find out how long the conditional actually is.
my @ newlines = ( $ c =~ /\n/gs ) ;
my $ cond_lines = 1 + $# newlines ;
# We want to check the first line inside the block
# starting at the end of the conditional, so remove:
# 1) any blank line termination
# 2) any opening brace { on end of the line
# 3) any do (...) {
my $ continuation = 0 ;
my $ check = 0 ;
$ s =~ s/^.*\bdo\b// ;
$ s =~ s/^\s*{// ;
if ( $ s =~ s/^\s*\\// ) {
$ continuation = 1 ;
}
if ( $ s =~ s/^\s*?\n// ) {
$ check = 1 ;
$ cond_lines + + ;
}
# Also ignore a loop construct at the end of a
# preprocessor statement.
if ( ( $ prevline =~ /^.\s*#\s*define\s/ ||
$ prevline =~ /\\\s*$/ ) && $ continuation == 0 ) {
$ check = 0 ;
}
my $ cond_ptr = - 1 ;
$ continuation = 0 ;
while ( $ cond_ptr != $ cond_lines ) {
$ cond_ptr = $ cond_lines ;
# If we see an #else/#elif then the code
# is not linear.
if ( $ s =~ /^\s*\#\s*(?:else|elif)/ ) {
$ check = 0 ;
}
# Ignore:
# 1) blank lines, they should be at 0,
# 2) preprocessor lines, and
# 3) labels.
if ( $ continuation ||
$ s =~ /^\s*?\n/ ||
$ s =~ /^\s*#\s*?/ ||
$ s =~ /^\s*$Ident\s*:/ ) {
$ continuation = ( $ s =~ /^.*?\\\n/ ) ? 1 : 0 ;
if ( $ s =~ s/^.*?\n// ) {
$ cond_lines + + ;
}
}
}
my ( undef , $ sindent ) = line_stats ( "+" . $ s ) ;
my $ stat_real = raw_line ( $ linenr , $ cond_lines ) ;
# Check if either of these lines are modified, else
# this is not this patch's fault.
if ( ! defined ( $ stat_real ) ||
$ stat !~ /^\+/ && $ stat_real !~ /^\+/ ) {
$ check = 0 ;
}
if ( defined ( $ stat_real ) && $ cond_lines > 1 ) {
$ stat_real = "[...]\n$stat_real" ;
}
#print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
if ( $ check && ( ( $ sindent % 8 ) != 0 ||
( $ sindent <= $ indent && $ s ne '' ) ) ) {
WARN ( "SUSPECT_CODE_INDENT" ,
"suspect code indent for conditional statements ($indent, $sindent)\n" . $ herecurr . "$stat_real\n" ) ;
}
}
# Track the 'values' across context and added lines.
my $ opline = $ line ; $ opline =~ s/^./ / ;
my ( $ curr_values , $ curr_vars ) =
annotate_values ( $ opline . "\n" , $ prev_values ) ;
$ curr_values = $ prev_values . $ curr_values ;
if ( $ dbg_values ) {
my $ outline = $ opline ; $ outline =~ s/\t/ /g ;
print "$linenr > .$outline\n" ;
print "$linenr > $curr_values\n" ;
print "$linenr > $curr_vars\n" ;
}
$ prev_values = substr ( $ curr_values , - 1 ) ;
#ignore lines not being added
next if ( $ line =~ /^[^\+]/ ) ;
# TEST: allow direct testing of the type matcher.
if ( $ dbg_type ) {
if ( $ line =~ /^.\s*$Declare\s*$/ ) {
ERROR ( "TEST_TYPE" ,
"TEST: is type\n" . $ herecurr ) ;
} elsif ( $ dbg_type > 1 && $ line =~ /^.+($Declare)/ ) {
ERROR ( "TEST_NOT_TYPE" ,
"TEST: is not type ($1 is)\n" . $ herecurr ) ;
}
next ;
}
# TEST: allow direct testing of the attribute matcher.
if ( $ dbg_attr ) {
if ( $ line =~ /^.\s*$Modifier\s*$/ ) {
ERROR ( "TEST_ATTR" ,
"TEST: is attr\n" . $ herecurr ) ;
} elsif ( $ dbg_attr > 1 && $ line =~ /^.+($Modifier)/ ) {
ERROR ( "TEST_NOT_ATTR" ,
"TEST: is not attr ($1 is)\n" . $ herecurr ) ;
}
next ;
}
# check for initialisation to aggregates open brace on the next line
if ( $ line =~ /^.\s*{/ &&
$ prevline =~ /(?:^|[^=])=\s*$/ ) {
ERROR ( "OPEN_BRACE" ,
"that open brace { should be on the previous line\n" . $ hereprev ) ;
}
#
# Checks which are anchored on the added line.
#
# check for malformed paths in #include statements (uses RAW line)
if ( $ rawline =~ m {^.\s*\#\s*include\s+[<"](.*)[">]} ) {
my $ path = $ 1 ;
if ( $ path =~ m {//} ) {
ERROR ( "MALFORMED_INCLUDE" ,
"malformed #include filename\n" . $ herecurr ) ;
}
if ( $ path =~ "^uapi/" && $ realfile =~ m @\binclude/uapi/@ ) {
ERROR ( "UAPI_INCLUDE" ,
"No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $ herecurr ) ;
}
}
# no C99 // comments
if ( $ line =~ m {//} ) {
if ( ERROR ( "C99_COMMENTS" ,
"do not use C99 // comments\n" . $ herecurr ) &&
$ fix ) {
my $ line = $ fixed [ $ linenr - 1 ] ;
if ( $ line =~ /\/\/(.*)$/ ) {
my $ comment = trim ( $ 1 ) ;
$ fixed [ $ linenr - 1 ] =~ s@\/\/(.*)$@/\* $comment \*/@ ;
}
}
}
# Remove C99 comments.
$ line =~ s@//.*@@ ;
$ opline =~ s@//.*@@ ;
# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
# the whole statement.
#print "APW <$lines[$realline_next - 1]>\n";
if ( defined $ realline_next &&
exists $ lines [ $ realline_next - 1 ] &&
! defined $ suppress_export { $ realline_next } &&
( $ lines [ $ realline_next - 1 ] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$ lines [ $ realline_next - 1 ] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/ ) ) {
# Handle definitions which produce identifiers with
# a prefix:
# XXX(foo);
# EXPORT_SYMBOL(something_foo);
my $ name = $ 1 ;
if ( $ stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
$ name =~ /^${Ident}_$2/ ) {
#print "FOO C name<$name>\n";
$ suppress_export { $ realline_next } = 1 ;
} elsif ( $ stat !~ / ( ? :
\ n . } \ s * $|
^ . DEFINE_ $ Ident \ ( \ Q $ name \ E \ ) |
^ . DECLARE_ $ Ident \ ( \ Q $ name \ E \ ) |
^ . LIST_HEAD \ ( \ Q $ name \ E \ ) |
^ . ( ? : $ Storage \ s + ) ? $ Type \ s * \ ( \ s * \ * \ s * \ Q $ name \ E \ s * \ ) \ s * \ ( |
\ b \ Q $ name \ E ( ? : \ s + $ Attribute ) * \ s * ( ? : ; |= | \ [ | \ ( )
) / x ) {
#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
$ suppress_export { $ realline_next } = 2 ;
} else {
$ suppress_export { $ realline_next } = 1 ;
}
}
if ( ! defined $ suppress_export { $ linenr } &&
$ prevline =~ /^.\s*$/ &&
( $ line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$ line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/ ) ) {
#print "FOO B <$lines[$linenr - 1]>\n";
$ suppress_export { $ linenr } = 2 ;
}
if ( defined $ suppress_export { $ linenr } &&
$ suppress_export { $ linenr } == 2 ) {
WARN ( "EXPORT_SYMBOL" ,
"EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $ herecurr ) ;
}
# check for global initialisers.
if ( $ line =~ /^\+(\s*$Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/ ) {
if ( ERROR ( "GLOBAL_INITIALISERS" ,
"do not initialise globals to 0 or NULL\n" .
$ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/ ;
}
}
# check for static initialisers.
if ( $ line =~ /^\+.*\bstatic\s.*=\s*(0|NULL|false)\s*;/ ) {
if ( ERROR ( "INITIALISED_STATIC" ,
"do not initialise statics to 0 or NULL\n" .
$ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/ ;
}
}
# check for static const char * arrays.
if ( $ line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/ ) {
WARN ( "STATIC_CONST_CHAR_ARRAY" ,
"static const char * array should probably be static const char * const\n" .
$ herecurr ) ;
}
# check for static char foo[] = "bar" declarations.
if ( $ line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/ ) {
WARN ( "STATIC_CONST_CHAR_ARRAY" ,
"static char array declaration should probably be static const char\n" .
$ herecurr ) ;
}
# check for non-global char *foo[] = {"bar", ...} declarations.
if ( $ line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/ ) {
WARN ( "STATIC_CONST_CHAR_ARRAY" ,
"char * array declaration might be better as static const\n" .
$ herecurr ) ;
}
# check for function declarations without arguments like "int foo()"
if ( $ line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/ ) {
if ( ERROR ( "FUNCTION_WITHOUT_ARGS" ,
"Bad function definition - $1() should probably be $1(void)\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/ ;
}
}
# * goes on variable not on type
# (char*[ const])
while ( $ line =~ m {(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g ) {
#print "AA<$1>\n";
my ( $ ident , $ from , $ to ) = ( $ 1 , $ 2 , $ 2 ) ;
# Should start with a space.
$ to =~ s/^(\S)/ $1/ ;
# Should not end with a space.
$ to =~ s/\s+$// ;
# '*'s should not have spaces between.
while ( $ to =~ s/\*\s+\*/\*\*/ ) {
}
## print "1: from<$from> to<$to> ident<$ident>\n";
if ( $ from ne $ to ) {
if ( ERROR ( "POINTER_LOCATION" ,
"\"(foo$from)\" should be \"(foo$to)\"\n" . $ herecurr ) &&
$ fix ) {
my $ sub_from = $ ident ;
my $ sub_to = $ ident ;
$ sub_to =~ s/\Q$from\E/$to/ ;
$ fixed [ $ linenr - 1 ] =~
s@\Q$sub_from\E@$sub_to@ ;
}
}
}
while ( $ line =~ m {(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g ) {
#print "BB<$1>\n";
my ( $ match , $ from , $ to , $ ident ) = ( $ 1 , $ 2 , $ 2 , $ 3 ) ;
# Should start with a space.
$ to =~ s/^(\S)/ $1/ ;
# Should not end with a space.
$ to =~ s/\s+$// ;
# '*'s should not have spaces between.
while ( $ to =~ s/\*\s+\*/\*\*/ ) {
}
# Modifiers should have spaces.
$ to =~ s/(\b$Modifier$)/$1 / ;
## print "2: from<$from> to<$to> ident<$ident>\n";
if ( $ from ne $ to && $ ident !~ /^$Modifier$/ ) {
if ( ERROR ( "POINTER_LOCATION" ,
"\"foo${from}bar\" should be \"foo${to}bar\"\n" . $ herecurr ) &&
$ fix ) {
my $ sub_from = $ match ;
my $ sub_to = $ match ;
$ sub_to =~ s/\Q$from\E/$to/ ;
$ fixed [ $ linenr - 1 ] =~
s@\Q$sub_from\E@$sub_to@ ;
}
}
}
# function brace can't be on same line, except for #defines of do while,
# or if closed on same line
2015-11-30 13:35:23 +01:00
if ( ( $ line =~ /$Type\s*$Ident\(.*\).*\s\{/ ) and
! ( $ line =~ /\#\s*define.*do\s\{/ ) and ! ( $ line =~ /}/ ) ) {
2014-06-25 21:22:49 -07:00
ERROR ( "OPEN_BRACE" ,
"open brace '{' following function declarations go on the next line\n" . $ herecurr ) ;
}
# open braces for enum, union and struct go on the same line.
if ( $ line =~ /^.\s*{/ &&
$ prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/ ) {
ERROR ( "OPEN_BRACE" ,
"open brace '{' following $1 go on the same line\n" . $ hereprev ) ;
}
# missing space after union, struct or enum definition
if ( $ line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/ ) {
if ( WARN ( "SPACING" ,
"missing space after $1 definition\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/ ;
}
}
# Function pointer declarations
# check spacing between type, funcptr, and args
# canonical declaration is "type (*funcptr)(args...)"
if ( $ line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/ ) {
my $ declare = $ 1 ;
my $ pre_pointer_space = $ 2 ;
my $ post_pointer_space = $ 3 ;
my $ funcname = $ 4 ;
my $ post_funcname_space = $ 5 ;
my $ pre_args_space = $ 6 ;
# the $Declare variable will capture all spaces after the type
# so check it for a missing trailing missing space but pointer return types
# don't need a space so don't warn for those.
my $ post_declare_space = "" ;
if ( $ declare =~ /(\s+)$/ ) {
$ post_declare_space = $ 1 ;
$ declare = rtrim ( $ declare ) ;
}
if ( $ declare !~ /\*$/ && $ post_declare_space =~ /^$/ ) {
WARN ( "SPACING" ,
"missing space after return type\n" . $ herecurr ) ;
$ post_declare_space = " " ;
}
# unnecessary space "type ( *funcptr)(args...)"
if ( defined $ pre_pointer_space &&
$ pre_pointer_space =~ /^\s/ ) {
WARN ( "SPACING" ,
"Unnecessary space after function pointer open parenthesis\n" . $ herecurr ) ;
}
# unnecessary space "type (* funcptr)(args...)"
if ( defined $ post_pointer_space &&
$ post_pointer_space =~ /^\s/ ) {
WARN ( "SPACING" ,
"Unnecessary space before function pointer name\n" . $ herecurr ) ;
}
# unnecessary space "type (*funcptr )(args...)"
if ( defined $ post_funcname_space &&
$ post_funcname_space =~ /^\s/ ) {
WARN ( "SPACING" ,
"Unnecessary space after function pointer name\n" . $ herecurr ) ;
}
# unnecessary space "type (*funcptr) (args...)"
if ( defined $ pre_args_space &&
$ pre_args_space =~ /^\s/ ) {
WARN ( "SPACING" ,
"Unnecessary space before function pointer arguments\n" . $ herecurr ) ;
}
if ( show_type ( "SPACING" ) && $ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex ;
}
}
# check for spacing round square brackets; allowed:
# 1. with a type on the left -- int [] a;
# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
# 3. inside a curly brace -- = { [0...10] = 5 }
while ( $ line =~ /(.*?\s)\[/g ) {
my ( $ where , $ prefix ) = ( $- [ 1 ] , $ 1 ) ;
if ( $ prefix !~ /$Type\s+$/ &&
( $ where != 0 || $ prefix !~ /^.\s+$/ ) &&
$ prefix !~ /[{,]\s+$/ ) {
if ( ERROR ( "BRACKET_SPACE" ,
"space prohibited before open square bracket '['\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(\+.*?)\s+\[/$1\[/ ;
}
}
}
# Check operator spacing.
if ( ! ( $ line =~ /\#\s*include/ ) ) {
my $ fixed_line = "" ;
my $ line_fixed = 0 ;
my $ ops = qr{
<<=|> >= | <=|> = |= = | != |
\ += | -= | \ *= | \ /= | % = | \ ^ = | \ | = | & = |
= > | - > | <<|> > | <|> |= | ! | ~ |
&& | \ | \ || , | \ ^ | \ + \ + | - - | & | \ || \ + | - | \ * | \ / | % |
\ ? : | \ ? | :
} x ;
my @ elements = split ( /($ops|;)/ , $ opline ) ;
## print("element count: <" . $#elements . ">\n");
## foreach my $el (@elements) {
## print("el: <$el>\n");
## }
my @ fix_elements = ( ) ;
my $ off = 0 ;
foreach my $ el ( @ elements ) {
push ( @ fix_elements , substr ( $ rawline , $ off , length ( $ el ) ) ) ;
$ off += length ( $ el ) ;
}
$ off = 0 ;
my $ blank = copy_spacing ( $ opline ) ;
my $ last_after = - 1 ;
for ( my $ n = 0 ; $ n < $# elements ; $ n += 2 ) {
my $ good = $ fix_elements [ $ n ] . $ fix_elements [ $ n + 1 ] ;
## print("n: <$n> good: <$good>\n");
$ off += length ( $ elements [ $ n ] ) ;
# Pick up the preceding and succeeding characters.
my $ ca = substr ( $ opline , 0 , $ off ) ;
my $ cc = '' ;
if ( length ( $ opline ) >= ( $ off + length ( $ elements [ $ n + 1 ] ) ) ) {
$ cc = substr ( $ opline , $ off + length ( $ elements [ $ n + 1 ] ) ) ;
}
my $ cb = "$ca$;$cc" ;
my $ a = '' ;
$ a = 'V' if ( $ elements [ $ n ] ne '' ) ;
$ a = 'W' if ( $ elements [ $ n ] =~ /\s$/ ) ;
$ a = 'C' if ( $ elements [ $ n ] =~ /$;$/ ) ;
$ a = 'B' if ( $ elements [ $ n ] =~ /(\[|\()$/ ) ;
$ a = 'O' if ( $ elements [ $ n ] eq '' ) ;
$ a = 'E' if ( $ ca =~ /^\s*$/ ) ;
my $ op = $ elements [ $ n + 1 ] ;
my $ c = '' ;
if ( defined $ elements [ $ n + 2 ] ) {
$ c = 'V' if ( $ elements [ $ n + 2 ] ne '' ) ;
$ c = 'W' if ( $ elements [ $ n + 2 ] =~ /^\s/ ) ;
$ c = 'C' if ( $ elements [ $ n + 2 ] =~ /^$;/ ) ;
$ c = 'B' if ( $ elements [ $ n + 2 ] =~ /^(\)|\]|;)/ ) ;
$ c = 'O' if ( $ elements [ $ n + 2 ] eq '' ) ;
$ c = 'E' if ( $ elements [ $ n + 2 ] =~ /^\s*\\$/ ) ;
} else {
$ c = 'E' ;
}
my $ ctx = "${a}x${c}" ;
my $ at = "(ctx:$ctx)" ;
my $ ptr = substr ( $ blank , 0 , $ off ) . "^" ;
my $ hereptr = "$hereline$ptr\n" ;
# Pull out the value of this operator.
my $ op_type = substr ( $ curr_values , $ off + 1 , 1 ) ;
# Get the full operator variant.
my $ opv = $ op . substr ( $ curr_vars , $ off , 1 ) ;
# Ignore operators passed as parameters.
if ( $ op_type ne 'V' &&
$ ca =~ /\s$/ && $ cc =~ /^\s*,/ ) {
# # Ignore comments
# } elsif ($op =~ /^$;+$/) {
# ; should have either the end of line or a space or \ after it
} elsif ( $ op eq ';' ) {
if ( $ ctx !~ /.x[WEBC]/ &&
$ cc !~ /^\\/ && $ cc !~ /^;/ ) {
if ( ERROR ( "SPACING" ,
"space required after that '$op' $at\n" . $ hereptr ) ) {
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
$ line_fixed = 1 ;
}
}
# // is a comment
} elsif ( $ op eq '//' ) {
# : when part of a bitfield
} elsif ( $ opv eq ':B' ) {
# skip the bitfield test for now
# No spaces for:
# ->
} elsif ( $ op eq '->' ) {
if ( $ ctx =~ /Wx.|.xW/ ) {
if ( ERROR ( "SPACING" ,
"spaces prohibited around that '$op' $at\n" . $ hereptr ) ) {
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s/^\s+// ;
}
$ line_fixed = 1 ;
}
}
# , must have a space on the right.
} elsif ( $ op eq ',' ) {
if ( $ ctx !~ /.x[WEC]/ && $ cc !~ /^}/ ) {
if ( ERROR ( "SPACING" ,
"space required after that '$op' $at\n" . $ hereptr ) ) {
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
$ line_fixed = 1 ;
$ last_after = $ n ;
}
}
# '*' as part of a type definition -- reported already.
} elsif ( $ opv eq '*_' ) {
#warn "'*' is part of type\n";
# unary operators should have a space before and
# none after. May be left adjacent to another
# unary operator, or a cast
} elsif ( $ op eq '!' || $ op eq '~' ||
$ opv eq '*U' || $ opv eq '-U' ||
$ opv eq '&U' || $ opv eq '&&U' ) {
if ( $ ctx !~ /[WEBC]x./ && $ ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/ ) {
if ( ERROR ( "SPACING" ,
"space required before that '$op' $at\n" . $ hereptr ) ) {
if ( $ n != $ last_after + 2 ) {
$ good = $ fix_elements [ $ n ] . " " . ltrim ( $ fix_elements [ $ n + 1 ] ) ;
$ line_fixed = 1 ;
}
}
}
if ( $ op eq '*' && $ cc =~ /\s*$Modifier\b/ ) {
# A unary '*' may be const
} elsif ( $ ctx =~ /.xW/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited after that '$op' $at\n" . $ hereptr ) ) {
$ good = $ fix_elements [ $ n ] . rtrim ( $ fix_elements [ $ n + 1 ] ) ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s/^\s+// ;
}
$ line_fixed = 1 ;
}
}
# unary ++ and unary -- are allowed no space on one side.
} elsif ( $ op eq '++' or $ op eq '--' ) {
if ( $ ctx !~ /[WEOBC]x[^W]/ && $ ctx !~ /[^W]x[WOBEC]/ ) {
if ( ERROR ( "SPACING" ,
"space required one side of that '$op' $at\n" . $ hereptr ) ) {
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
$ line_fixed = 1 ;
}
}
if ( $ ctx =~ /Wx[BE]/ ||
( $ ctx =~ /Wx./ && $ cc =~ /^;/ ) ) {
if ( ERROR ( "SPACING" ,
"space prohibited before that '$op' $at\n" . $ hereptr ) ) {
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
$ line_fixed = 1 ;
}
}
if ( $ ctx =~ /ExW/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited after that '$op' $at\n" . $ hereptr ) ) {
$ good = $ fix_elements [ $ n ] . trim ( $ fix_elements [ $ n + 1 ] ) ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s/^\s+// ;
}
$ line_fixed = 1 ;
}
}
# << and >> may either have or not have spaces both sides
} elsif ( $ op eq '<<' or $ op eq '>>' or
$ op eq '&' or $ op eq '^' or $ op eq '|' or
$ op eq '+' or $ op eq '-' or
$ op eq '*' or $ op eq '/' or
$ op eq '%' )
{
if ( $ ctx =~ /Wx[^WCE]|[^WCE]xW/ ) {
if ( ERROR ( "SPACING" ,
"need consistent spacing around '$op' $at\n" . $ hereptr ) ) {
$ good = rtrim ( $ fix_elements [ $ n ] ) . " " . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s/^\s+// ;
}
$ line_fixed = 1 ;
}
}
# A colon needs no spaces before when it is
# terminating a case value or a label.
} elsif ( $ opv eq ':C' || $ opv eq ':L' ) {
if ( $ ctx =~ /Wx./ ) {
if ( ERROR ( "SPACING" ,
"space prohibited before that '$op' $at\n" . $ hereptr ) ) {
$ good = rtrim ( $ fix_elements [ $ n ] ) . trim ( $ fix_elements [ $ n + 1 ] ) ;
$ line_fixed = 1 ;
}
}
# All the others need spaces both sides.
} elsif ( $ ctx !~ /[EWC]x[CWE]/ ) {
my $ ok = 0 ;
# Ignore email addresses <foo@bar>
if ( ( $ op eq '<' &&
$ cc =~ /^\S+\@\S+>/ ) ||
( $ op eq '>' &&
$ ca =~ /<\S+\@\S+$/ ) )
{
$ ok = 1 ;
}
# messages are ERROR, but ?: are CHK
if ( $ ok == 0 ) {
my $ msg_type = \ & ERROR ;
$ msg_type = \ & CHK if ( ( $ op eq '?:' || $ op eq '?' || $ op eq ':' ) && $ ctx =~ /VxV/ ) ;
if ( & { $ msg_type } ( "SPACING" ,
"spaces required around that '$op' $at\n" . $ hereptr ) ) {
$ good = rtrim ( $ fix_elements [ $ n ] ) . " " . trim ( $ fix_elements [ $ n + 1 ] ) . " " ;
if ( defined $ fix_elements [ $ n + 2 ] ) {
$ fix_elements [ $ n + 2 ] =~ s/^\s+// ;
}
$ line_fixed = 1 ;
}
}
}
$ off += length ( $ elements [ $ n + 1 ] ) ;
## print("n: <$n> GOOD: <$good>\n");
$ fixed_line = $ fixed_line . $ good ;
}
if ( ( $# elements % 2 ) == 0 ) {
$ fixed_line = $ fixed_line . $ fix_elements [ $# elements ] ;
}
if ( $ fix && $ line_fixed && $ fixed_line ne $ fixed [ $ linenr - 1 ] ) {
$ fixed [ $ linenr - 1 ] = $ fixed_line ;
}
}
# check for whitespace before a non-naked semicolon
if ( $ line =~ /^\+.*\S\s+;\s*$/ ) {
if ( WARN ( "SPACING" ,
"space prohibited before semicolon\n" . $ herecurr ) &&
$ fix ) {
1 while $ fixed [ $ linenr - 1 ] =~
s/^(\+.*\S)\s+;/$1;/ ;
}
}
# check for multiple assignments
if ( $ line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/ ) {
CHK ( "MULTIPLE_ASSIGNMENTS" ,
"multiple assignments should be avoided\n" . $ herecurr ) ;
}
## # check for multiple declarations, allowing for a function declaration
## # continuation.
## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
##
## # Remove any bracketed sections to ensure we do not
## # falsly report the parameters of functions.
## my $ln = $line;
## while ($ln =~ s/\([^\(\)]*\)//g) {
## }
## if ($ln =~ /,/) {
## WARN("MULTIPLE_DECLARATION",
## "declaring multiple variables together should be avoided\n" . $herecurr);
## }
## }
#need space before brace following if, while, etc
2015-11-30 13:35:23 +01:00
if ( ( $ line =~ /\(.*\)\{/ && $ line !~ /\($Type\)\{/ ) ||
$ line =~ /do\{/ ) {
2014-06-25 21:22:49 -07:00
if ( ERROR ( "SPACING" ,
"space required before the open brace '{'\n" . $ herecurr ) &&
$ fix ) {
2018-07-03 11:47:31 +05:30
$ fixed [ $ linenr - 1 ] =~ s/^(\+.*(?:do|\)))\{/$1 {/ ;
2014-06-25 21:22:49 -07:00
}
}
## # check for blank lines before declarations
## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ &&
## $prevrawline =~ /^.\s*$/) {
## WARN("SPACING",
## "No blank lines before declarations\n" . $hereprev);
## }
##
# closing brace should have a space following it when it has anything
# on the line
if ( $ line =~ /}(?!(?:,|;|\)))\S/ ) {
if ( ERROR ( "SPACING" ,
"space required after that close brace '}'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/}((?!(?:,|;|\)))\S)/} $1/ ;
}
}
# check spacing on square brackets
if ( $ line =~ /\[\s/ && $ line !~ /\[\s*$/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited after that open square bracket '['\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/\[\s+/\[/ ;
}
}
if ( $ line =~ /\s\]/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited before that close square bracket ']'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/\s+\]/\]/ ;
}
}
# check spacing on parentheses
if ( $ line =~ /\(\s/ && $ line !~ /\(\s*(?:\\)?$/ &&
$ line !~ /for\s*\(\s+;/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited after that open parenthesis '('\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/\(\s+/\(/ ;
}
}
if ( $ line =~ /(\s+)\)/ && $ line !~ /^.\s*\)/ &&
$ line !~ /for\s*\(.*;\s+\)/ &&
$ line !~ /:\s+\)/ ) {
if ( ERROR ( "SPACING" ,
"space prohibited before that close parenthesis ')'\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/\s+\)/\)/ ;
}
}
#goto labels aren't indented, allow a single space however
if ( $ line =~ /^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
! ( $ line =~ /^. [A-Za-z\d_]+:/ ) and ! ( $ line =~ /^.\s+default:/ ) ) {
if ( WARN ( "INDENTED_LABEL" ,
"labels should not be indented\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(.)\s+/$1/ ;
}
}
# return is not a function
if ( defined ( $ stat ) && $ stat =~ /^.\s*return(\s*)\(/s ) {
my $ spacing = $ 1 ;
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/ ) {
my $ value = $ 1 ;
$ value = deparenthesize ( $ value ) ;
if ( $ value =~ m/^\s*$FuncArg\s*(?:\?|$)/ ) {
ERROR ( "RETURN_PARENTHESES" ,
"return is not a function, parentheses are not required\n" . $ herecurr ) ;
}
} elsif ( $ spacing !~ /\s+/ ) {
ERROR ( "SPACING" ,
"space required before the open parenthesis '('\n" . $ herecurr ) ;
}
}
# unnecessary return in a void function
# at end-of-function, with the previous line a single leading tab, then return;
# and the line before that not a goto label target like "out:"
if ( $ sline =~ /^[ \+]}\s*$/ &&
$ prevline =~ /^\+\treturn\s*;\s*$/ &&
$ linenr >= 3 &&
$ lines [ $ linenr - 3 ] =~ /^[ +]/ &&
$ lines [ $ linenr - 3 ] !~ /^[ +]\s*$Ident\s*:/ ) {
WARN ( "RETURN_VOID" ,
"void function return statements are not generally useful\n" . $ hereprev ) ;
}
# if statements using unnecessary parentheses - ie: if ((foo == bar))
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ line =~ /\bif\s*((?:\(\s*){2,})/ ) {
my $ openparens = $ 1 ;
my $ count = $ openparens =~ tr @ \ ( @ \ ( @ ;
my $ msg = "" ;
if ( $ line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/ ) {
my $ comp = $ 4 ; #Not $1 because of $LvalOrFunc
$ msg = " - maybe == should be = ?" if ( $ comp eq "==" ) ;
WARN ( "UNNECESSARY_PARENTHESES" ,
"Unnecessary parentheses$msg\n" . $ herecurr ) ;
}
}
# Return of what appears to be an errno should normally be -'ve
if ( $ line =~ /^.\s*return\s*(E[A-Z]*)\s*;/ ) {
my $ name = $ 1 ;
if ( $ name ne 'EOF' && $ name ne 'ERROR' ) {
WARN ( "USE_NEGATIVE_ERRNO" ,
"return of an errno should typically be -ve (return -$1)\n" . $ herecurr ) ;
}
}
# Need a space before open parenthesis after if, while etc
if ( $ line =~ /\b(if|while|for|switch)\(/ ) {
if ( ERROR ( "SPACING" ,
"space required before the open parenthesis '('\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/\b(if|while|for|switch)\(/$1 \(/ ;
}
}
# Check for illegal assignment in if conditional -- and check for trailing
# statements after the conditional.
if ( $ line =~ /do\s*(?!{)/ ) {
( $ stat , $ cond , $ line_nr_next , $ remain_next , $ off_next ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 )
if ( ! defined $ stat ) ;
my ( $ stat_next ) = ctx_statement_block ( $ line_nr_next ,
$ remain_next , $ off_next ) ;
$ stat_next =~ s/\n./\n /g ;
##print "stat<$stat> stat_next<$stat_next>\n";
if ( $ stat_next =~ /^\s*while\b/ ) {
# If the statement carries leading newlines,
# then count those as offsets.
my ( $ whitespace ) =
( $ stat_next =~ /^((?:\s*\n[+-])*\s*)/s ) ;
my $ offset =
statement_rawlines ( $ whitespace ) - 1 ;
$ suppress_whiletrailers { $ line_nr_next +
$ offset } = 1 ;
}
}
if ( ! defined $ suppress_whiletrailers { $ linenr } &&
defined ( $ stat ) && defined ( $ cond ) &&
$ line =~ /\b(?:if|while|for)\s*\(/ && $ line !~ /^.\s*#/ ) {
my ( $ s , $ c ) = ( $ stat , $ cond ) ;
if ( $ c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s ) {
ERROR ( "ASSIGN_IN_IF" ,
"do not use assignment in if condition\n" . $ herecurr ) ;
}
# Find out what is on the end of the line after the
# conditional.
substr ( $ s , 0 , length ( $ c ) , '' ) ;
$ s =~ s/\n.*//g ;
$ s =~ s/$;//g ; # Remove any comments
if ( length ( $ c ) && $ s !~ /^\s*{?\s*\\*\s*$/ &&
$ c !~ /}\s*while\s*/ )
{
# Find out how long the conditional actually is.
my @ newlines = ( $ c =~ /\n/gs ) ;
my $ cond_lines = 1 + $# newlines ;
my $ stat_real = '' ;
$ stat_real = raw_line ( $ linenr , $ cond_lines )
. "\n" if ( $ cond_lines ) ;
if ( defined ( $ stat_real ) && $ cond_lines > 1 ) {
$ stat_real = "[...]\n$stat_real" ;
}
ERROR ( "TRAILING_STATEMENTS" ,
"trailing statements should be on next line\n" . $ herecurr . $ stat_real ) ;
}
}
# Check for bitwise tests written as boolean
if ( $ line =~ /
( ? :
( ? : \ [ | \ ( | \ & \ & | \ | \ | )
\ s * 0 [ xX ] [ 0 - 9 ] + \ s *
( ? : \ & \ & | \ | \ | )
|
( ? : \ & \ & | \ | \ | )
\ s * 0 [ xX ] [ 0 - 9 ] + \ s *
( ? : \ & \ & | \ | \ || \ ) | \ ] )
) / x )
{
WARN ( "HEXADECIMAL_BOOLEAN_TEST" ,
"boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $ herecurr ) ;
}
# if and else should not have general statements after it
if ( $ line =~ /^.\s*(?:}\s*)?else\b(.*)/ ) {
my $ s = $ 1 ;
$ s =~ s/$;//g ; # Remove any comments
if ( $ s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/ ) {
ERROR ( "TRAILING_STATEMENTS" ,
"trailing statements should be on next line\n" . $ herecurr ) ;
}
}
# if should not continue a brace
if ( $ line =~ /}\s*if\b/ ) {
ERROR ( "TRAILING_STATEMENTS" ,
"trailing statements should be on next line\n" .
$ herecurr ) ;
}
# case and default should not have general statements after them
if ( $ line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
$ line !~ / \ G ( ? :
( ? : \ s * $; * ) ( ? : \ s * { ) ? ( ? : \ s * $; * ) ( ? : \ s * \ \ ) ? \ s * $|
\ s * return \ s +
) / xg )
{
ERROR ( "TRAILING_STATEMENTS" ,
"trailing statements should be on next line\n" . $ herecurr ) ;
}
2014-10-13 15:19:35 -07:00
# Check for }<nl>else {, these must be at the same
# indent level to be relevant to each other.
if ( $ prevline =~ /}\s*$/ and $ line =~ /^.\s*else\s*/ and
$ previndent == $ indent ) {
2014-06-25 21:22:49 -07:00
ERROR ( "ELSE_AFTER_BRACE" ,
2014-10-13 15:19:35 -07:00
"else should follow close brace '}'\n" . $ hereprev ) ;
2014-06-25 21:22:49 -07:00
}
if ( $ prevline =~ /}\s*$/ and $ line =~ /^.\s*while\s*/ and
$ previndent == $ indent ) {
my ( $ s , $ c ) = ctx_statement_block ( $ linenr , $ realcnt , 0 ) ;
# Find out what is on the end of the line after the
# conditional.
substr ( $ s , 0 , length ( $ c ) , '' ) ;
$ s =~ s/\n.*//g ;
if ( $ s =~ /^\s*;/ ) {
ERROR ( "WHILE_AFTER_BRACE" ,
"while should follow close brace '}'\n" . $ hereprev ) ;
}
}
#Specific variable tests
while ( $ line =~ m {($Constant|$Lval)}g ) {
my $ var = $ 1 ;
#gcc binary extension
if ( $ var =~ /^$Binary$/ ) {
if ( WARN ( "GCC_BINARY_CONSTANT" ,
"Avoid gcc v4.3+ binary constant extension: <$var>\n" . $ herecurr ) &&
$ fix ) {
my $ hexval = sprintf ( "0x%x" , oct ( $ var ) ) ;
$ fixed [ $ linenr - 1 ] =~
s/\b$var\b/$hexval/ ;
}
}
#CamelCase
if ( $ var !~ /^$Constant$/ &&
$ var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
#Ignore Page<foo> variants
$ var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
$ var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ ) {
while ( $ var =~ m {($Ident)}g ) {
my $ word = $ 1 ;
next if ( $ word !~ /[A-Z][a-z]|[a-z][A-Z]/ ) ;
if ( $ check ) {
seed_camelcase_includes ( ) ;
if ( ! $ file && ! $ camelcase_file_seeded ) {
seed_camelcase_file ( $ realfile ) ;
$ camelcase_file_seeded = 1 ;
}
}
if ( ! defined $ camelcase { $ word } ) {
$ camelcase { $ word } = 1 ;
CHK ( "CAMELCASE" ,
"Avoid CamelCase: <$word>\n" . $ herecurr ) ;
}
}
}
}
#no spaces allowed after \ in define
if ( $ line =~ /\#\s*define.*\\\s+$/ ) {
if ( WARN ( "WHITESPACE_AFTER_LINE_CONTINUATION" ,
"Whitespace after \\ makes next lines useless\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\s+$// ;
}
}
#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
if ( $ tree && $ rawline =~ m {^.\s*\#\s*include\s*\<asm\/(.*)\.h\>} ) {
my $ file = "$1.h" ;
my $ checkfile = "include/linux/$file" ;
if ( - f "$root/$checkfile" &&
$ realfile ne $ checkfile &&
$ 1 !~ /$allowed_asm_includes/ )
{
if ( $ realfile =~ m {^arch/} ) {
CHK ( "ARCH_INCLUDE_LINUX" ,
"Consider using #include <linux/$file> instead of <asm/$file>\n" . $ herecurr ) ;
} else {
WARN ( "INCLUDE_LINUX" ,
"Use #include <linux/$file> instead of <asm/$file>\n" . $ herecurr ) ;
}
}
}
# multi-statement macros should be enclosed in a do while loop, grab the
# first statement and ensure its the whole macro if its not enclosed
# in a known good container
if ( $ realfile !~ m @/vmlinux.lds.h$@ &&
$ line =~ /^.\s*\#\s*define\s*$Ident(\()?/ ) {
my $ ln = $ linenr ;
my $ cnt = $ realcnt ;
my ( $ off , $ dstat , $ dcond , $ rest ) ;
my $ ctx = '' ;
( $ dstat , $ dcond , $ ln , $ cnt , $ off ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 ) ;
$ ctx = $ dstat ;
#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
#print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
$ dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*// ;
$ dstat =~ s/$;//g ;
$ dstat =~ s/\\\n.//g ;
$ dstat =~ s/^\s*//s ;
$ dstat =~ s/\s*$//s ;
# Flatten any parentheses and braces
while ( $ dstat =~ s/\([^\(\)]*\)/1/ ||
$ dstat =~ s/\{[^\{\}]*\}/1/ ||
$ dstat =~ s/\[[^\[\]]*\]/1/ )
{
}
# Flatten any obvious string concatentation.
while ( $ dstat =~ s/("X*")\s*$Ident/$1/ ||
$ dstat =~ s/$Ident\s*("X*")/$1/ )
{
}
my $ exceptions = qr{
$ Declare |
module_param_named |
MODULE_PARM_DESC |
DECLARE_PER_CPU |
DEFINE_PER_CPU |
__typeof__ \ ( |
union |
struct |
\ . $ Ident \ s *= \ s * |
^ \ " | \ " $
} x ;
#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
if ( $ dstat ne '' &&
$ dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(),
$ dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo();
$ dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz
$ dstat !~ /^'X'$/ && # character constants
$ dstat !~ /$exceptions/ &&
$ dstat !~ /^\.$Ident\s*=/ && # .foo =
$ dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
$ dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
$ dstat !~ /^for\s*$Constant$/ && # for (...)
$ dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar()
$ dstat !~ /^do\s*{/ && # do {...
2015-11-30 13:35:23 +01:00
$ dstat !~ /^\(\{/ && # ({...
2014-06-25 21:22:49 -07:00
$ ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/ )
{
$ ctx =~ s/\n*$// ;
my $ herectx = $ here . "\n" ;
my $ cnt = statement_rawlines ( $ ctx ) ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n + + ) {
$ herectx . = raw_line ( $ linenr , $ n ) . "\n" ;
}
if ( $ dstat =~ /;/ ) {
ERROR ( "MULTISTATEMENT_MACRO_USE_DO_WHILE" ,
"Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx" ) ;
} else {
ERROR ( "COMPLEX_MACRO" ,
"Macros with complex values should be enclosed in parenthesis\n" . "$herectx" ) ;
}
}
# check for line continuations outside of #defines, preprocessor #, and asm
} else {
if ( $ prevline !~ /^..*\\$/ &&
$ line !~ /^\+\s*\#.*\\$/ && # preprocessor
$ line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm
$ line =~ /^\+.*\\$/ ) {
WARN ( "LINE_CONTINUATIONS" ,
"Avoid unnecessary line continuations\n" . $ herecurr ) ;
}
}
# do {} while (0) macro tests:
# single-statement macros do not need to be enclosed in do while (0) loop,
# macro should not end with a semicolon
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ realfile !~ m @/vmlinux.lds.h$@ &&
$ line =~ /^.\s*\#\s*define\s+$Ident(\()?/ ) {
my $ ln = $ linenr ;
my $ cnt = $ realcnt ;
my ( $ off , $ dstat , $ dcond , $ rest ) ;
my $ ctx = '' ;
( $ dstat , $ dcond , $ ln , $ cnt , $ off ) =
ctx_statement_block ( $ linenr , $ realcnt , 0 ) ;
$ ctx = $ dstat ;
$ dstat =~ s/\\\n.//g ;
if ( $ dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/ ) {
my $ stmts = $ 2 ;
my $ semis = $ 3 ;
$ ctx =~ s/\n*$// ;
my $ cnt = statement_rawlines ( $ ctx ) ;
my $ herectx = $ here . "\n" ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n + + ) {
$ herectx . = raw_line ( $ linenr , $ n ) . "\n" ;
}
if ( ( $ stmts =~ tr /;/ ; / ) == 1 &&
$ stmts !~ /^\s*(if|while|for|switch)\b/ ) {
WARN ( "SINGLE_STATEMENT_DO_WHILE_MACRO" ,
"Single statement macros should not use a do {} while (0) loop\n" . "$herectx" ) ;
}
if ( defined $ semis && $ semis ne "" ) {
WARN ( "DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON" ,
"do {} while (0) macros should not be semicolon terminated\n" . "$herectx" ) ;
}
} elsif ( $ dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/ ) {
$ ctx =~ s/\n*$// ;
my $ cnt = statement_rawlines ( $ ctx ) ;
my $ herectx = $ here . "\n" ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n + + ) {
$ herectx . = raw_line ( $ linenr , $ n ) . "\n" ;
}
WARN ( "TRAILING_SEMICOLON" ,
"macros should not use a trailing semicolon\n" . "$herectx" ) ;
}
}
# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
# all assignments may have only one of the following with an assignment:
# .
# ALIGN(...)
# VMLINUX_SYMBOL(...)
if ( $ realfile eq 'vmlinux.lds.h' && $ line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/ ) {
WARN ( "MISSING_VMLINUX_SYMBOL" ,
"vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $ herecurr ) ;
}
# check for redundant bracing round if etc
if ( $ line =~ /(^.*)\bif\b/ && $ 1 !~ /else\s*$/ ) {
my ( $ level , $ endln , @ chunks ) =
ctx_statement_full ( $ linenr , $ realcnt , 1 ) ;
#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
if ( $# chunks > 0 && $ level == 0 ) {
my @ allowed = ( ) ;
my $ allow = 0 ;
my $ seen = 0 ;
my $ herectx = $ here . "\n" ;
my $ ln = $ linenr - 1 ;
for my $ chunk ( @ chunks ) {
my ( $ cond , $ block ) = @ { $ chunk } ;
# If the condition carries leading newlines, then count those as offsets.
my ( $ whitespace ) = ( $ cond =~ /^((?:\s*\n[+-])*\s*)/s ) ;
my $ offset = statement_rawlines ( $ whitespace ) - 1 ;
$ allowed [ $ allow ] = 0 ;
#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
# We have looked at and allowed this specific line.
$ suppress_ifbraces { $ ln + $ offset } = 1 ;
$ herectx . = "$rawlines[$ln + $offset]\n[...]\n" ;
$ ln += statement_rawlines ( $ block ) - 1 ;
substr ( $ block , 0 , length ( $ cond ) , '' ) ;
$ seen + + if ( $ block =~ /^\s*{/ ) ;
#print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
if ( statement_lines ( $ cond ) > 1 ) {
#print "APW: ALLOWED: cond<$cond>\n";
$ allowed [ $ allow ] = 1 ;
}
if ( $ block =~ /\b(?:if|for|while)\b/ ) {
#print "APW: ALLOWED: block<$block>\n";
$ allowed [ $ allow ] = 1 ;
}
if ( statement_block_size ( $ block ) > 1 ) {
#print "APW: ALLOWED: lines block<$block>\n";
$ allowed [ $ allow ] = 1 ;
}
$ allow + + ;
}
if ( $ seen ) {
my $ sum_allowed = 0 ;
foreach ( @ allowed ) {
$ sum_allowed += $ _ ;
}
2014-09-22 16:48:50 -04:00
if ( $ sum_allowed != 0 && $ sum_allowed != $ allow
&& $ seen != $ allow ) {
2014-06-25 21:22:49 -07:00
CHK ( "BRACES" ,
"braces {} should be used on all arms of this statement\n" . $ herectx ) ;
}
}
}
}
if ( ! defined $ suppress_ifbraces { $ linenr - 1 } &&
$ line =~ /\b(if|while|for|else)\b/ ) {
my $ allowed = 0 ;
# Check the pre-context.
if ( substr ( $ line , 0 , $- [ 0 ] ) =~ /(\}\s*)$/ ) {
#print "APW: ALLOWED: pre<$1>\n";
$ allowed = 1 ;
}
my ( $ level , $ endln , @ chunks ) =
ctx_statement_full ( $ linenr , $ realcnt , $- [ 0 ] ) ;
# Check the condition.
my ( $ cond , $ block ) = @ { $ chunks [ 0 ] } ;
#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
if ( defined $ cond ) {
substr ( $ block , 0 , length ( $ cond ) , '' ) ;
}
if ( statement_lines ( $ cond ) > 1 ) {
#print "APW: ALLOWED: cond<$cond>\n";
$ allowed = 1 ;
}
if ( $ block =~ /\b(?:if|for|while)\b/ ) {
#print "APW: ALLOWED: block<$block>\n";
$ allowed = 1 ;
}
if ( statement_block_size ( $ block ) > 1 ) {
#print "APW: ALLOWED: lines block<$block>\n";
$ allowed = 1 ;
}
# Check the post-context.
if ( defined $ chunks [ 1 ] ) {
my ( $ cond , $ block ) = @ { $ chunks [ 1 ] } ;
if ( defined $ cond ) {
substr ( $ block , 0 , length ( $ cond ) , '' ) ;
}
if ( $ block =~ /^\s*\{/ ) {
#print "APW: ALLOWED: chunk-1 block<$block>\n";
$ allowed = 1 ;
}
}
}
# check for unnecessary blank lines around braces
if ( ( $ line =~ /^.\s*}\s*$/ && $ prevrawline =~ /^.\s*$/ ) ) {
CHK ( "BRACES" ,
"Blank lines aren't necessary before a close brace '}'\n" . $ hereprev ) ;
}
if ( ( $ rawline =~ /^.\s*$/ && $ prevline =~ /^..*{\s*$/ ) ) {
CHK ( "BRACES" ,
"Blank lines aren't necessary after an open brace '{'\n" . $ hereprev ) ;
}
# no volatiles please
my $ asm_volatile = qr{ \ b(__asm__|asm) \ s+(__volatile__|volatile) \ b } ;
if ( $ line =~ /\bvolatile\b/ && $ line !~ /$asm_volatile/ ) {
WARN ( "VOLATILE" ,
"Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $ herecurr ) ;
}
# warn about #if 0
if ( $ line =~ /^.\s*\#\s*if\s+0\b/ ) {
CHK ( "REDUNDANT_CODE" ,
"if this code is redundant consider removing it\n" .
$ herecurr ) ;
}
# check for needless "if (<foo>) fn(<foo>)" uses
if ( $ prevline =~ /\bif\s*\(\s*($Lval)\s*\)/ ) {
my $ expr = '\s*\(\s*' . quotemeta ( $ 1 ) . '\s*\)\s*;' ;
if ( $ line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/ ) {
WARN ( 'NEEDLESS_IF' ,
"$1(NULL) is safe this check is probably not required\n" . $ hereprev ) ;
}
}
# check for bad placement of section $InitAttribute (e.g.: __initdata)
if ( $ line =~ /(\b$InitAttribute\b)/ ) {
my $ attr = $ 1 ;
if ( $ line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/ ) {
my $ ptr = $ 1 ;
my $ var = $ 2 ;
if ( ( ( $ ptr =~ /\b(union|struct)\s+$attr\b/ &&
ERROR ( "MISPLACED_INIT" ,
"$attr should be placed after $var\n" . $ herecurr ) ) ||
( $ ptr !~ /\b(union|struct)\s+$attr\b/ &&
WARN ( "MISPLACED_INIT" ,
"$attr should be placed after $var\n" . $ herecurr ) ) ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e ;
}
}
}
# check for $InitAttributeData (ie: __initdata) with const
if ( $ line =~ /\bconst\b/ && $ line =~ /($InitAttributeData)/ ) {
my $ attr = $ 1 ;
$ attr =~ /($InitAttributePrefix)(.*)/ ;
my $ attr_prefix = $ 1 ;
my $ attr_type = $ 2 ;
if ( ERROR ( "INIT_ATTRIBUTE" ,
"Use of const init definition must use ${attr_prefix}initconst\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/$InitAttributeData/${attr_prefix}initconst/ ;
}
}
# check for $InitAttributeConst (ie: __initconst) without const
if ( $ line !~ /\bconst\b/ && $ line =~ /($InitAttributeConst)/ ) {
my $ attr = $ 1 ;
if ( ERROR ( "INIT_ATTRIBUTE" ,
"Use of $attr requires a separate use of const\n" . $ herecurr ) &&
$ fix ) {
my $ lead = $ fixed [ $ linenr - 1 ] =~
/(^\+\s*(?:static\s+))/ ;
$ lead = rtrim ( $ 1 ) ;
$ lead = "$lead " if ( $ lead !~ /^\+$/ ) ;
$ lead = "${lead}const " ;
$ fixed [ $ linenr - 1 ] =~ s/(^\+\s*(?:static\s+))/$lead/ ;
}
}
# don't use __constant_<foo> functions outside of include/uapi/
if ( $ realfile !~ m @^include/uapi/@ &&
$ line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/ ) {
my $ constant_func = $ 1 ;
my $ func = $ constant_func ;
$ func =~ s/^__constant_// ;
if ( WARN ( "CONSTANT_CONVERSION" ,
"$constant_func should be $func\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\b$constant_func\b/$func/g ;
}
}
# prefer usleep_range over udelay
if ( $ line =~ /\budelay\s*\(\s*(\d+)\s*\)/ ) {
my $ delay = $ 1 ;
# ignore udelay's < 10, however
if ( ! ( $ delay < 10 ) ) {
CHK ( "USLEEP_RANGE" ,
"usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $ herecurr ) ;
}
if ( $ delay > 2000 ) {
WARN ( "LONG_UDELAY" ,
"long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $ herecurr ) ;
}
}
# warn about unexpectedly long msleep's
if ( $ line =~ /\bmsleep\s*\((\d+)\);/ ) {
if ( $ 1 < 20 ) {
WARN ( "MSLEEP" ,
"msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $ herecurr ) ;
}
}
# check for comparisons of jiffies
if ( $ line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/ ) {
WARN ( "JIFFIES_COMPARISON" ,
"Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $ herecurr ) ;
}
# check for comparisons of get_jiffies_64()
if ( $ line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/ ) {
WARN ( "JIFFIES_COMPARISON" ,
"Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $ herecurr ) ;
}
# warn about spacing in #ifdefs
if ( $ line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/ ) {
if ( ERROR ( "SPACING" ,
"exactly one space required after that #$1\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~
s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 / ;
}
}
# check for spinlock_t definitions without a comment.
if ( $ line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
$ line =~ /^.\s*(DEFINE_MUTEX)\s*\(/ ) {
my $ which = $ 1 ;
if ( ! ctx_has_comment ( $ first_line , $ linenr ) ) {
CHK ( "UNCOMMENTED_DEFINITION" ,
"$1 definition without comment\n" . $ herecurr ) ;
}
}
# check for memory barriers without a comment.
if ( $ line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/ ) {
if ( ! ctx_has_comment ( $ first_line , $ linenr ) ) {
WARN ( "MEMORY_BARRIER" ,
"memory barrier without comment\n" . $ herecurr ) ;
}
}
# check of hardware specific defines
if ( $ line =~ m @^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $ realfile !~ m @include/asm-@ ) {
CHK ( "ARCH_DEFINES" ,
"architecture specific defines should be avoided\n" . $ herecurr ) ;
}
# Check that the storage class is at the beginning of a declaration
if ( $ line =~ /\b$Storage\b/ && $ line !~ /^.\s*$Storage\b/ ) {
WARN ( "STORAGE_CLASS" ,
"storage class should be at the beginning of the declaration\n" . $ herecurr )
}
# check the location of the inline attribute, that it is between
# storage class and type.
if ( $ line =~ /\b$Type\s+$Inline\b/ ||
$ line =~ /\b$Inline\s+$Storage\b/ ) {
ERROR ( "INLINE_LOCATION" ,
"inline keyword should sit between storage class and type\n" . $ herecurr ) ;
}
# Check for __inline__ and __inline, prefer inline
if ( $ realfile !~ m @\binclude/uapi/@ &&
$ line =~ /\b(__inline__|__inline)\b/ ) {
if ( WARN ( "INLINE" ,
"plain inline is preferred over $1\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\b(__inline__|__inline)\b/inline/ ;
}
}
# Check for __attribute__ packed, prefer __packed
if ( $ realfile !~ m @\binclude/uapi/@ &&
$ line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/ ) {
WARN ( "PREFER_PACKED" ,
"__packed is preferred over __attribute__((packed))\n" . $ herecurr ) ;
}
# Check for __attribute__ aligned, prefer __aligned
if ( $ realfile !~ m @\binclude/uapi/@ &&
$ line =~ /\b__attribute__\s*\(\s*\(.*aligned/ ) {
WARN ( "PREFER_ALIGNED" ,
"__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $ herecurr ) ;
}
# Check for __attribute__ format(printf, prefer __printf
if ( $ realfile !~ m @\binclude/uapi/@ &&
$ line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/ ) {
if ( WARN ( "PREFER_PRINTF" ,
"__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex ;
}
}
# Check for __attribute__ format(scanf, prefer __scanf
if ( $ realfile !~ m @\binclude/uapi/@ &&
$ line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/ ) {
if ( WARN ( "PREFER_SCANF" ,
"__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex ;
}
}
# check for sizeof(&)
if ( $ line =~ /\bsizeof\s*\(\s*\&/ ) {
WARN ( "SIZEOF_ADDRESS" ,
"sizeof(& should be avoided\n" . $ herecurr ) ;
}
# check for sizeof without parenthesis
if ( $ line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/ ) {
if ( WARN ( "SIZEOF_PARENTHESIS" ,
"sizeof $1 should be sizeof($1)\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex ;
}
}
# check for line continuations in quoted strings with odd counts of "
if ( $ rawline =~ /\\$/ && $ rawline =~ tr /"/ " / % 2 ) {
WARN ( "LINE_CONTINUATIONS" ,
"Avoid line continuations in quoted strings\n" . $ herecurr ) ;
}
# check for struct spinlock declarations
if ( $ line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/ ) {
WARN ( "USE_SPINLOCK_T" ,
"struct spinlock should be spinlock_t\n" . $ herecurr ) ;
}
# check for seq_printf uses that could be seq_puts
if ( $ sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/ ) {
my $ fmt = get_quoted_string ( $ line , $ rawline ) ;
if ( $ fmt ne "" && $ fmt !~ /[^\\]\%/ ) {
if ( WARN ( "PREFER_SEQ_PUTS" ,
"Prefer seq_puts to seq_printf\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/\bseq_printf\b/seq_puts/ ;
}
}
}
# Check for misused memsets
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s ) {
my $ ms_addr = $ 2 ;
my $ ms_val = $ 7 ;
my $ ms_size = $ 12 ;
if ( $ ms_size =~ /^(0x|)0$/i ) {
ERROR ( "MEMSET" ,
"memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n" ) ;
} elsif ( $ ms_size =~ /^(0x|)1$/i ) {
WARN ( "MEMSET" ,
"single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n" ) ;
}
}
# typecasts on min/max could be min_t/max_t
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/ ) {
if ( defined $ 2 || defined $ 7 ) {
my $ call = $ 1 ;
my $ cast1 = deparenthesize ( $ 2 ) ;
my $ arg1 = $ 3 ;
my $ cast2 = deparenthesize ( $ 7 ) ;
my $ arg2 = $ 8 ;
my $ cast ;
if ( $ cast1 ne "" && $ cast2 ne "" && $ cast1 ne $ cast2 ) {
$ cast = "$cast1 or $cast2" ;
} elsif ( $ cast1 ne "" ) {
$ cast = $ cast1 ;
} else {
$ cast = $ cast2 ;
}
WARN ( "MINMAX" ,
"$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n" ) ;
}
}
# check usleep_range arguments
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/ ) {
my $ min = $ 1 ;
my $ max = $ 7 ;
if ( $ min eq $ max ) {
WARN ( "USLEEP_RANGE" ,
"usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n" ) ;
} elsif ( $ min =~ /^\d+$/ && $ max =~ /^\d+$/ &&
$ min > $ max ) {
WARN ( "USLEEP_RANGE" ,
"usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n" ) ;
}
}
# check for naked sscanf
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ line =~ /\bsscanf\b/ &&
( $ stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
$ stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ &&
$ stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/ ) ) {
my $ lc = $ stat =~ tr @ \ n @@ ;
$ lc = $ lc + $ linenr ;
my $ stat_real = raw_line ( $ linenr , 0 ) ;
for ( my $ count = $ linenr + 1 ; $ count <= $ lc ; $ count + + ) {
$ stat_real = $ stat_real . "\n" . raw_line ( $ count , 0 ) ;
}
WARN ( "NAKED_SSCANF" ,
"unchecked sscanf return value\n" . "$here\n$stat_real\n" ) ;
}
# check for simple sscanf that should be kstrto<foo>
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ line =~ /\bsscanf\b/ ) {
my $ lc = $ stat =~ tr @ \ n @@ ;
$ lc = $ lc + $ linenr ;
my $ stat_real = raw_line ( $ linenr , 0 ) ;
for ( my $ count = $ linenr + 1 ; $ count <= $ lc ; $ count + + ) {
$ stat_real = $ stat_real . "\n" . raw_line ( $ count , 0 ) ;
}
if ( $ stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/ ) {
my $ format = $ 6 ;
my $ count = $ format =~ tr @%@%@ ;
if ( $ count == 1 &&
$ format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/ ) {
WARN ( "SSCANF_TO_KSTRTO" ,
"Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n" ) ;
}
}
}
# check for new externs in .h files.
if ( $ realfile =~ /\.h$/ &&
$ line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s ) {
if ( CHK ( "AVOID_EXTERNS" ,
"extern prototypes should be avoided in .h files\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/(.*)\bextern\b\s*(.*)/$1$2/ ;
}
}
# check for new externs in .c files.
if ( $ realfile =~ /\.c$/ && defined $ stat &&
$ stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s )
{
my $ function_name = $ 1 ;
my $ paren_space = $ 2 ;
my $ s = $ stat ;
if ( defined $ cond ) {
substr ( $ s , 0 , length ( $ cond ) , '' ) ;
}
if ( $ s =~ /^\s*;/ &&
$ function_name ne 'uninitialized_var' )
{
WARN ( "AVOID_EXTERNS" ,
"externs should be avoided in .c files\n" . $ herecurr ) ;
}
if ( $ paren_space =~ /\n/ ) {
WARN ( "FUNCTION_ARGUMENTS" ,
"arguments for function declarations should follow identifier\n" . $ herecurr ) ;
}
} elsif ( $ realfile =~ /\.c$/ && defined $ stat &&
$ stat =~ /^.\s*extern\s+/ )
{
WARN ( "AVOID_EXTERNS" ,
"externs should be avoided in .c files\n" . $ herecurr ) ;
}
# check for pointless casting of kmalloc return
if ( $ line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/ ) {
WARN ( "UNNECESSARY_CASTS" ,
"unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $ herecurr ) ;
}
# alloc style
# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/ ) {
CHK ( "ALLOC_SIZEOF_STRUCT" ,
"Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $ herecurr ) ;
}
# check for multiple semicolons
if ( $ line =~ /;\s*;\s*$/ ) {
if ( WARN ( "ONE_SEMICOLON" ,
"Statements terminations use 1 semicolon\n" . $ herecurr ) &&
$ fix ) {
$ fixed [ $ linenr - 1 ] =~ s/(\s*;\s*){2,}$/;/g ;
}
}
# check for case / default statements not preceeded by break/fallthrough/switch
if ( $ line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/ ) {
my $ has_break = 0 ;
my $ has_statement = 0 ;
my $ count = 0 ;
my $ prevline = $ linenr ;
while ( $ prevline > 1 && $ count < 3 && ! $ has_break ) {
$ prevline - - ;
my $ rline = $ rawlines [ $ prevline - 1 ] ;
my $ fline = $ lines [ $ prevline - 1 ] ;
last if ( $ fline =~ /^\@\@/ ) ;
next if ( $ fline =~ /^\-/ ) ;
next if ( $ fline =~ /^.(?:\s*(?:case\s+(?:$Ident|$Constant)[\s$;]*|default):[\s$;]*)*$/ ) ;
$ has_break = 1 if ( $ rline =~ /fall[\s_-]*(through|thru)/i ) ;
next if ( $ fline =~ /^.[\s$;]*$/ ) ;
$ has_statement = 1 ;
$ count + + ;
$ has_break = 1 if ( $ fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/ ) ;
}
if ( ! $ has_break && $ has_statement ) {
WARN ( "MISSING_BREAK" ,
"Possible switch case/default not preceeded by break or fallthrough comment\n" . $ herecurr ) ;
}
}
# check for switch/default statements without a break;
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
defined $ stat &&
$ stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g ) {
my $ ctx = '' ;
my $ herectx = $ here . "\n" ;
my $ cnt = statement_rawlines ( $ stat ) ;
for ( my $ n = 0 ; $ n < $ cnt ; $ n + + ) {
$ herectx . = raw_line ( $ linenr , $ n ) . "\n" ;
}
WARN ( "DEFAULT_NO_BREAK" ,
"switch default: should use break\n" . $ herectx ) ;
}
# check for comparisons against true and false
if ( $ line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i ) {
my $ lead = $ 1 ;
my $ arg = $ 2 ;
my $ test = $ 3 ;
my $ otype = $ 4 ;
my $ trail = $ 5 ;
my $ op = "!" ;
( $ arg , $ otype ) = ( $ otype , $ arg ) if ( $ arg =~ /^(?:true|false)$/i ) ;
my $ type = lc ( $ otype ) ;
if ( $ type =~ /^(?:true|false)$/ ) {
if ( ( "$test" eq "==" && "$type" eq "true" ) ||
( "$test" eq "!=" && "$type" eq "false" ) ) {
$ op = "" ;
}
CHK ( "BOOL_COMPARISON" ,
"Using comparison to $otype is error prone\n" . $ herecurr ) ;
}
}
# check for semaphores initialized locked
if ( $ line =~ /^.\s*sema_init.+,\W?0\W?\)/ ) {
WARN ( "CONSIDER_COMPLETION" ,
"consider using a completion\n" . $ herecurr ) ;
}
# check for %L{u,d,i} in strings
my $ string ;
while ( $ line =~ /(?:^|")([X\t]*)(?:"|$)/g ) {
$ string = substr ( $ rawline , $- [ 1 ] , $+ [ 1 ] - $- [ 1 ] ) ;
$ string =~ s/%%/__/g ;
if ( $ string =~ /(?<!%)%L[udi]/ ) {
WARN ( "PRINTF_L" ,
"\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $ herecurr ) ;
last ;
}
}
# Mode permission misuses where it seems decimal should be octal
# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
if ( $ ^ V && $ ^ V ge 5.10 .0 &&
$ line =~ /$mode_perms_search/ ) {
foreach my $ entry ( @ mode_permission_funcs ) {
my $ func = $ entry - > [ 0 ] ;
my $ arg_pos = $ entry - > [ 1 ] ;
my $ skip_args = "" ;
if ( $ arg_pos > 1 ) {
$ arg_pos - - ;
$ skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}" ;
}
my $ test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]" ;
if ( $ line =~ /$test/ ) {
my $ val = $ 1 ;
$ val = $ 6 if ( $ skip_args ne "" ) ;
if ( $ val !~ /^0$/ &&
( ( $ val =~ /^$Int$/ && $ val !~ /^$Octal$/ ) ||
length ( $ val ) ne 4 ) ) {
ERROR ( "NON_OCTAL_PERMISSIONS" ,
"Use 4 digit octal (0777) not decimal permissions\n" . $ herecurr ) ;
}
}
}
}
}
# If we have no input at all, then there is nothing to report on
# so just keep quiet.
if ( $# rawlines == - 1 ) {
exit ( 0 ) ;
}
# In mailback mode only produce a report in the negative, for
# things that appear to be patches.
if ( $ mailback && ( $ clean == 1 || ! $ is_patch ) ) {
exit ( 0 ) ;
}
# This is not a patch, and we are are in 'no-patch' mode so
# just keep quiet.
if ( ! $ chk_patch && ! $ is_patch ) {
exit ( 0 ) ;
}
if ( ! $ is_patch ) {
ERROR ( "NOT_UNIFIED_DIFF" ,
"Does not appear to be a unified-diff format patch\n" ) ;
}
2015-03-19 10:38:23 +01:00
if ( $ is_patch && $ subject_trailing_dot != 0 ) {
ERROR ( "SUBJECT_TRAILING_DOT" ,
"The subject of the patch should not end with a dot.\n" ) ;
}
2014-06-25 21:22:49 -07:00
if ( $ is_patch && $ chk_signoff && $ signoff == 0 ) {
ERROR ( "MISSING_SIGN_OFF" ,
"Missing Signed-off-by: line(s)\n" ) ;
}
print report_dump ( ) ;
if ( $ summary && ! ( $ clean == 1 && $ quiet == 1 ) ) {
print "$filename " if ( $ summary_file ) ;
if ( $ cnt_error > 0 ) {
print "Patch not according to coding guidelines! please fix.\n" ;
print "total: $cnt_error errors, $cnt_warn warnings, " .
( ( $ check ) ? "$cnt_chk checks, " : "" ) .
"$cnt_lines lines checked\n" ; exit 1 ;
} else {
print "total: $cnt_warn warnings, " .
( ( $ check ) ? "$cnt_chk checks, " : "" ) .
"$cnt_lines lines checked\n" ;
print "Patch found to have warnings, please fix if necessary.\n" if ( $ cnt_warn > 0 ) ;
exit 2 ;
}
print "\n" if ( $ quiet == 0 ) ;
}
if ( $ quiet == 0 ) {
if ( $ ^ V lt 5.10 .0 ) {
print ( "NOTE: perl $^V is not modern enough to detect all possible issues.\n" ) ;
print ( "An upgrade to at least perl v5.10.0 is suggested.\n\n" ) ;
}
# If there were whitespace errors which cleanpatch can fix
# then suggest that.
if ( $ rpt_cleaners ) {
print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n" ;
print " scripts/cleanfile\n\n" ;
$ rpt_cleaners = 0 ;
}
}
hash_show_words ( \ % use_type , "Used" ) ;
hash_show_words ( \ % ignore_type , "Ignored" ) ;
if ( $ clean == 0 && $ fix && "@rawlines" ne "@fixed" ) {
my $ newfile = $ filename ;
$ newfile . = ".EXPERIMENTAL-checkpatch-fixes" if ( ! $ fix_inplace ) ;
my $ linecount = 0 ;
my $ f ;
open ( $ f , '>' , $ newfile )
or die "$P: Can't open $newfile for write\n" ;
foreach my $ fixed_line ( @ fixed ) {
$ linecount + + ;
if ( $ file ) {
if ( $ linecount > 3 ) {
$ fixed_line =~ s/^\+// ;
print $ f $ fixed_line . "\n" ;
}
} else {
print $ f $ fixed_line . "\n" ;
}
}
close ( $ f ) ;
if ( ! $ quiet ) {
print << "EOM" ;
Wrote EXPERIMENTAL - - fix correction ( s ) to '$newfile'
Do _NOT_ trust the results written to this file .
Do _NOT_ submit these changes without inspecting them for correctness .
This EXPERIMENTAL file is simply a convenience to help rewrite patches .
No warranties , expressed or implied ...
EOM
}
}
if ( $ clean == 1 && $ quiet == 0 ) {
print "$vname has no obvious style problems and is ready for submission.\n"
}
if ( $ clean == 0 && $ quiet == 0 ) {
print << "EOM" ;
$ vname has style problems , please review .
If any of these errors are false positives , please report
them to the maintainer , see MAINTAINERS
EOM
}
return $ clean ;
}